<commit_before>use std::sync::{Arc,Mutex};
use std::collections::HashMap;
use std::io::BufReader;
use rustls::{ResolvesServerCert, SignatureScheme, PrivateKey};
use rustls::sign::{CertifiedKey, RSASigningKey};
use rustls::internal::pemfile;
use webpki::DNSNameRef;

use sozu_command::messages::{CertificateAndKey, CertFingerprint};
use sozu_command::certificate::calculate_fingerprint_from_der;

use network::trie::TrieNode;

struct TlsData {
  pub cert:     CertifiedKey,
  pub refcount: usize,
}

pub struct CertificateResolver {
  domains:      TrieNode<CertFingerprint>,
  certificates: HashMap<CertFingerprint, TlsData>,
}

impl CertificateResolver {
  pub fn new() -> CertificateResolver {
    CertificateResolver {
      domains:      TrieNode::root(),
      certificates: HashMap::new(),
    }
  }

  pub fn add_certificate(&mut self, certificate_and_key: CertificateAndKey) -> bool {

    let mut chain = Vec::new();

    let mut cert_reader = BufReader::new(certificate_and_key.certificate.as_bytes());
    let parsed_certs = pemfile::certs(&mut cert_reader);
    //info!("parsed: {:?}", parsed_cert);

    let mut names = vec!(String::from("https://lolcatho.st"));
    let mut fingerprint:Vec<u8> = Vec::new();
    if let Ok(certs) = parsed_certs {
      if !certs.is_empty() {
        fingerprint = calculate_fingerprint_from_der(&certs[0].0);
        info!("cert fingerprint: {:?}", fingerprint);

        // create a untrusted::Input
        // let input = untrusted::Input::from(&certs[0].0);
        // create an EndEntityCert
        // let ee = webpki::EndEntityCert::from(input).unwrap()
        // get names
        // let dns_names = ee.list_dns_names()
        // names.extend(dns_names.drain(..).map(|name| name.to_String()));

      }
      for cert in certs {
        chain.push(cert);
      }
    } else {
      return false;
    }

    for ref cert in certificate_and_key.certificate_chain.iter() {
      let mut chain_cert_reader = BufReader::new(cert.as_bytes());
      if let Ok(parsed_chain_certs) = pemfile::certs(&mut chain_cert_reader) {
        for cert in parsed_chain_certs {
          chain.push(cert);
        }
      }
    }

    let mut key_reader = BufReader::new(certificate_and_key.key.as_bytes());
    let parsed_key = pemfile::pkcs8_private_keys(&mut key_reader);

    if let Ok(keys) = parsed_key {
      if !keys.is_empty() {
        if let Ok(signing_key) = RSASigningKey::new(&keys[0]) {
          let certified = CertifiedKey::new(chain, Arc::new(Box::new(signing_key)));

          let data = TlsData {
            cert:     certified,
            refcount: 0,
          };

          let fingerprint = CertFingerprint(fingerprint);
          self.certificates.insert(fingerprint.clone(), data);
          for name in names.drain(..) {
            self.domains.domain_insert(name.into_bytes(), fingerprint.clone());
          }

          return true;
        }
      }
    }

    false
  }

  pub fn remove_certificate(&mut self, fingerprint: &CertFingerprint) {
    let must_delete = self.certificates.get(fingerprint).map(|data| data.refcount == 0).unwrap_or(false);

    if let Some(data) = self.certificates.get(fingerprint) {
      let cert = &data.cert.cert[0];
      let names = vec!(String::from("https://lolcatho.st"));

      // create a untrusted::Input
      // let input = untrusted::Input::from(&certs[0].0);
      // create an EndEntityCert
      // let ee = webpki::EndEntityCert::from(input).unwrap()
      // get names
      // let dns_names = ee.list_dns_names()
      // names.extend(dns_names.drain(..).map(|name| name.to_String()));

      for name in names {
        self.domains.domain_remove(&name.into_bytes());
      }
    }

    if must_delete {
      self.certificates.remove(fingerprint);
    }
  }

  pub fn add_front(&mut self, fingerprint: &CertFingerprint) -> bool {
    if self.certificates.contains_key(fingerprint) {
      self.certificates.get_mut(fingerprint).map(|data| data.refcount += 1);
      true
    } else {
      false
    }
  }

  pub fn remove_front(&mut self, fingerprint: &CertFingerprint) {
    self.certificates.get_mut(fingerprint).map(|data| data.refcount -= 1);

    let must_delete = self.certificates.get(fingerprint).map(|data| data.refcount == 0).unwrap_or(false);
    if must_delete {
      self.certificates.remove(fingerprint);
    }
  }
}

pub struct CertificateResolverWrapper(Mutex<CertificateResolver>);

impl CertificateResolverWrapper {
  pub fn new() -> CertificateResolverWrapper {
    CertificateResolverWrapper(Mutex::new(CertificateResolver::new()))
  }

  pub fn add_certificate(&self, certificate_and_key: CertificateAndKey) -> bool {
    if let Ok(ref mut resolver) = self.0.try_lock() {
      resolver.add_certificate(certificate_and_key)
    } else {
      false
    }
  }

  pub fn remove_certificate(&self, fingerprint: &CertFingerprint) {
    if let Ok(ref mut resolver) = self.0.try_lock() {
      resolver.remove_certificate(fingerprint)
    }

  }

  pub fn add_front(&self, fingerprint: &CertFingerprint) -> bool {
    if let Ok(ref mut resolver) = self.0.try_lock() {
      resolver.add_front(fingerprint)
    } else {
      false
    }
  }

  pub fn remove_front(&self, fingerprint: &CertFingerprint) {
    if let Ok(ref mut resolver) = self.0.try_lock() {
      resolver.remove_front(fingerprint)
    }
  }
}

impl ResolvesServerCert for CertificateResolverWrapper {
  fn resolve(
        &self,
        server_name: Option<DNSNameRef>,
        sigschemes: &[SignatureScheme]
    ) -> Option<CertifiedKey> {

    info!("trying to resolve name: {:?} for signature scheme: {:?}", server_name, sigschemes);
    if let Ok(ref mut resolver) = self.0.try_lock() {

    }

    None
  }
}

<commit_msg>move certificate and key parsing in a function<commit_after>use std::sync::{Arc,Mutex};
use std::collections::HashMap;
use std::io::BufReader;
use rustls::{ResolvesServerCert, SignatureScheme, PrivateKey};
use rustls::sign::{CertifiedKey, RSASigningKey};
use rustls::internal::pemfile;
use webpki::DNSNameRef;

use sozu_command::messages::{CertificateAndKey, CertFingerprint};
use sozu_command::certificate::calculate_fingerprint_from_der;

use network::trie::TrieNode;

struct TlsData {
  pub cert:     CertifiedKey,
  pub refcount: usize,
}

pub struct CertificateResolver {
  domains:      TrieNode<CertFingerprint>,
  certificates: HashMap<CertFingerprint, TlsData>,
}

impl CertificateResolver {
  pub fn new() -> CertificateResolver {
    CertificateResolver {
      domains:      TrieNode::root(),
      certificates: HashMap::new(),
    }
  }

  pub fn add_certificate(&mut self, certificate_and_key: CertificateAndKey) -> bool {

    if let Some(certified_key) = generate_certified_key(certificate_and_key) {
      let mut names = vec!(String::from("https://lolcatho.st"));
      let fingerprint = calculate_fingerprint_from_der(&certified_key.cert[0].0);
      info!("cert fingerprint: {:?}", fingerprint);
      // create a untrusted::Input
      // let input = untrusted::Input::from(&certs[0].0);
      // create an EndEntityCert
      // let ee = webpki::EndEntityCert::from(input).unwrap()
      // get names
      // let dns_names = ee.list_dns_names()
      // names.extend(dns_names.drain(..).map(|name| name.to_String()));

      let data = TlsData {
        cert:     certified_key,
        refcount: 0,
      };

      let fingerprint = CertFingerprint(fingerprint);
      self.certificates.insert(fingerprint.clone(), data);
      for name in names.drain(..) {
        self.domains.domain_insert(name.into_bytes(), fingerprint.clone());
      }

      true
    } else {
      false
    }
  }

  pub fn remove_certificate(&mut self, fingerprint: &CertFingerprint) {
    let must_delete = self.certificates.get(fingerprint).map(|data| data.refcount == 0).unwrap_or(false);

    if let Some(data) = self.certificates.get(fingerprint) {
      let cert = &data.cert.cert[0];
      let names = vec!(String::from("https://lolcatho.st"));

      // create a untrusted::Input
      // let input = untrusted::Input::from(&certs[0].0);
      // create an EndEntityCert
      // let ee = webpki::EndEntityCert::from(input).unwrap()
      // get names
      // let dns_names = ee.list_dns_names()
      // names.extend(dns_names.drain(..).map(|name| name.to_String()));

      for name in names {
        self.domains.domain_remove(&name.into_bytes());
      }
    }

    if must_delete {
      self.certificates.remove(fingerprint);
    }
  }

  pub fn add_front(&mut self, fingerprint: &CertFingerprint) -> bool {
    if self.certificates.contains_key(fingerprint) {
      self.certificates.get_mut(fingerprint).map(|data| data.refcount += 1);
      true
    } else {
      false
    }
  }

  pub fn remove_front(&mut self, fingerprint: &CertFingerprint) {
    self.certificates.get_mut(fingerprint).map(|data| data.refcount -= 1);

    let must_delete = self.certificates.get(fingerprint).map(|data| data.refcount == 0).unwrap_or(false);
    if must_delete {
      self.certificates.remove(fingerprint);
    }
  }
}

pub struct CertificateResolverWrapper(Mutex<CertificateResolver>);

impl CertificateResolverWrapper {
  pub fn new() -> CertificateResolverWrapper {
    CertificateResolverWrapper(Mutex::new(CertificateResolver::new()))
  }

  pub fn add_certificate(&self, certificate_and_key: CertificateAndKey) -> bool {
    if let Ok(ref mut resolver) = self.0.try_lock() {
      resolver.add_certificate(certificate_and_key)
    } else {
      false
    }
  }

  pub fn remove_certificate(&self, fingerprint: &CertFingerprint) {
    if let Ok(ref mut resolver) = self.0.try_lock() {
      resolver.remove_certificate(fingerprint)
    }

  }

  pub fn add_front(&self, fingerprint: &CertFingerprint) -> bool {
    if let Ok(ref mut resolver) = self.0.try_lock() {
      resolver.add_front(fingerprint)
    } else {
      false
    }
  }

  pub fn remove_front(&self, fingerprint: &CertFingerprint) {
    if let Ok(ref mut resolver) = self.0.try_lock() {
      resolver.remove_front(fingerprint)
    }
  }
}

impl ResolvesServerCert for CertificateResolverWrapper {
  fn resolve(
        &self,
        server_name: Option<DNSNameRef>,
        sigschemes: &[SignatureScheme]
    ) -> Option<CertifiedKey> {

    info!("trying to resolve name: {:?} for signature scheme: {:?}", server_name, sigschemes);
    if let Ok(ref mut resolver) = self.0.try_lock() {

    }

    None
  }
}

pub fn generate_certified_key(certificate_and_key: CertificateAndKey) -> Option<CertifiedKey> {
  let mut chain = Vec::new();

  let mut cert_reader = BufReader::new(certificate_and_key.certificate.as_bytes());
  let parsed_certs = pemfile::certs(&mut cert_reader);

  let mut fingerprint:Vec<u8> = Vec::new();
  if let Ok(certs) = parsed_certs {
    for cert in certs {
      chain.push(cert);
    }
  } else {
    return None;
  }

  for ref cert in certificate_and_key.certificate_chain.iter() {
    let mut chain_cert_reader = BufReader::new(cert.as_bytes());
    if let Ok(parsed_chain_certs) = pemfile::certs(&mut chain_cert_reader) {
      for cert in parsed_chain_certs {
        chain.push(cert);
      }
    }
  }

  let mut key_reader = BufReader::new(certificate_and_key.key.as_bytes());
  let parsed_key = pemfile::pkcs8_private_keys(&mut key_reader);

  if let Ok(keys) = parsed_key {
    if !keys.is_empty() {
      if let Ok(signing_key) = RSASigningKey::new(&keys[0]) {
        let certified = CertifiedKey::new(chain, Arc::new(Box::new(signing_key)));
        return Some(certified);
      }
    }
  }

  None
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// Test how overloaded deref interacts with borrows when DerefMut
// is implemented.

use std::ops::{Deref, DerefMut};

struct Own<T> {
    value: *mut T
}

impl<T> Deref<T> for Own<T> {
    fn deref<'a>(&'a self) -> &'a T {
        unsafe { &*self.value }
    }
}

impl<T> DerefMut<T> for Own<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { &mut *self.value }
    }
}

struct Point {
    x: int,
    y: int
}

impl Point {
    fn get(&self) -> (int, int) {
        (self.x, self.y)
    }

    fn set(&mut self, x: int, y: int) {
        self.x = x;
        self.y = y;
    }

    fn x_ref<'a>(&'a self) -> &'a int {
        &self.x
    }

    fn y_mut<'a>(&'a mut self) -> &'a mut int {
        &mut self.y
    }
}

fn deref_imm_field(x: Own<Point>) {
    let _i = &x.y;
}

fn deref_mut_field1(x: Own<Point>) {
    let _i = &mut x.y; //~ ERROR cannot borrow
}

fn deref_mut_field2(mut x: Own<Point>) {
    let _i = &mut x.y;
}

fn deref_extend_field<'a>(x: &'a Own<Point>) -> &'a int {
    &x.y
}

fn deref_extend_mut_field1<'a>(x: &'a Own<Point>) -> &'a mut int {
    &mut x.y //~ ERROR cannot borrow
}

fn deref_extend_mut_field2<'a>(x: &'a mut Own<Point>) -> &'a mut int {
    &mut x.y
}

fn assign_field1<'a>(x: Own<Point>) {
    x.y = 3; //~ ERROR cannot borrow
}

fn assign_field2<'a>(x: &'a Own<Point>) {
    x.y = 3; //~ ERROR cannot assign
}

fn assign_field3<'a>(x: &'a mut Own<Point>) {
    x.y = 3;
}

// FIXME(eddyb) #12825 This shouldn't attempt to call deref_mut.
/*
fn deref_imm_method(x: Own<Point>) {
    let _i = x.get();
}
*/

fn deref_mut_method1(x: Own<Point>) {
    x.set(0, 0); //~ ERROR cannot borrow
}

fn deref_mut_method2(mut x: Own<Point>) {
    x.set(0, 0);
}

fn deref_extend_method<'a>(x: &'a Own<Point>) -> &'a int {
    x.x_ref()
}

fn deref_extend_mut_method1<'a>(x: &'a Own<Point>) -> &'a mut int {
    x.y_mut() //~ ERROR cannot borrow
}

fn deref_extend_mut_method2<'a>(x: &'a mut Own<Point>) -> &'a mut int {
    x.y_mut()
}

fn assign_method1<'a>(x: Own<Point>) {
    *x.y_mut() = 3; //~ ERROR cannot borrow
}

fn assign_method2<'a>(x: &'a Own<Point>) {
    *x.y_mut() = 3; //~ ERROR cannot borrow
}

fn assign_method3<'a>(x: &'a mut Own<Point>) {
    *x.y_mut() = 3;
}

pub fn main() {}<commit_msg>compile-fail: Beef up borrowck test to include some scenarios where we borrow mutably twice in a row<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

// Test how overloaded deref interacts with borrows when DerefMut
// is implemented.

use std::ops::{Deref, DerefMut};

struct Own<T> {
    value: *mut T
}

impl<T> Deref<T> for Own<T> {
    fn deref<'a>(&'a self) -> &'a T {
        unsafe { &*self.value }
    }
}

impl<T> DerefMut<T> for Own<T> {
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { &mut *self.value }
    }
}

struct Point {
    x: int,
    y: int
}

impl Point {
    fn get(&self) -> (int, int) {
        (self.x, self.y)
    }

    fn set(&mut self, x: int, y: int) {
        self.x = x;
        self.y = y;
    }

    fn x_ref<'a>(&'a self) -> &'a int {
        &self.x
    }

    fn y_mut<'a>(&'a mut self) -> &'a mut int {
        &mut self.y
    }
}

fn deref_imm_field(x: Own<Point>) {
    let _i = &x.y;
}

fn deref_mut_field1(x: Own<Point>) {
    let _i = &mut x.y; //~ ERROR cannot borrow
}

fn deref_mut_field2(mut x: Own<Point>) {
    let _i = &mut x.y;
}

fn deref_extend_field<'a>(x: &'a Own<Point>) -> &'a int {
    &x.y
}

fn deref_extend_mut_field1<'a>(x: &'a Own<Point>) -> &'a mut int {
    &mut x.y //~ ERROR cannot borrow
}

fn deref_extend_mut_field2<'a>(x: &'a mut Own<Point>) -> &'a mut int {
    &mut x.y
}

fn deref_extend_mut_field3<'a>(x: &'a mut Own<Point>) {
    // Hmm, this is unfortunate, because with ~ it would work,
    // but it's presently the expected outcome. See `deref_extend_mut_field4`
    // for the workaround.

    let _x = &mut x.x;
    let _y = &mut x.y; //~ ERROR cannot borrow
}

fn deref_extend_mut_field4<'a>(x: &'a mut Own<Point>) {
    let p = &mut **x;
    let _x = &mut p.x;
    let _y = &mut p.y;
}

fn assign_field1<'a>(x: Own<Point>) {
    x.y = 3; //~ ERROR cannot borrow
}

fn assign_field2<'a>(x: &'a Own<Point>) {
    x.y = 3; //~ ERROR cannot assign
}

fn assign_field3<'a>(x: &'a mut Own<Point>) {
    x.y = 3;
}

fn assign_field4<'a>(x: &'a mut Own<Point>) {
    let _p: &mut Point = &mut **x;
    x.y = 3; //~ ERROR cannot borrow
}

// FIXME(eddyb) #12825 This shouldn't attempt to call deref_mut.
/*
fn deref_imm_method(x: Own<Point>) {
    let _i = x.get();
}
*/

fn deref_mut_method1(x: Own<Point>) {
    x.set(0, 0); //~ ERROR cannot borrow
}

fn deref_mut_method2(mut x: Own<Point>) {
    x.set(0, 0);
}

fn deref_extend_method<'a>(x: &'a Own<Point>) -> &'a int {
    x.x_ref()
}

fn deref_extend_mut_method1<'a>(x: &'a Own<Point>) -> &'a mut int {
    x.y_mut() //~ ERROR cannot borrow
}

fn deref_extend_mut_method2<'a>(x: &'a mut Own<Point>) -> &'a mut int {
    x.y_mut()
}

fn assign_method1<'a>(x: Own<Point>) {
    *x.y_mut() = 3; //~ ERROR cannot borrow
}

fn assign_method2<'a>(x: &'a Own<Point>) {
    *x.y_mut() = 3; //~ ERROR cannot borrow
}

fn assign_method3<'a>(x: &'a mut Own<Point>) {
    *x.y_mut() = 3;
}

pub fn main() {}
<|endoftext|>


<commit_before>// edition:2018

// Test that a feature gate is needed to use `impl Trait` as the
// return type of an async.

#![feature(arbitrary_self_types, async_await, await_macro)]

trait Trait<'a, 'b> { }
impl<T> Trait<'_, '_> for T { }

async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
    //~^ ERROR ambiguous lifetime bound
    (a, b)
}

fn main() {
    let _ = async_ret_impl_trait(&22, &44);
}
<commit_msg>Update src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs<commit_after>// edition:2018

// Test that a feature gate is needed to use `impl Trait` as the
// return type of an async.

#![feature(async_await)]

trait Trait<'a, 'b> { }
impl<T> Trait<'_, '_> for T { }

async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
    //~^ ERROR ambiguous lifetime bound
    (a, b)
}

fn main() {
    let _ = async_ret_impl_trait(&22, &44);
}
<|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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("InheritedBox", inherited=True, gecko_name="Visibility") %>

// TODO: collapse. Well, do tables first.
${helpers.single_keyword("visibility",
                         "visible hidden",
                         extra_gecko_values="collapse",
                         gecko_ffi_name="mVisible",
                         animation_value_type="ComputedValue",
                         spec="https://drafts.csswg.org/css-box/#propdef-visibility")}

// CSS Writing Modes Level 3
// https://drafts.csswg.org/css-writing-modes-3
${helpers.single_keyword("writing-mode",
                         "horizontal-tb vertical-rl vertical-lr",
                         extra_gecko_values="sideways-rl sideways-lr",
                         extra_gecko_aliases="lr=horizontal-tb lr-tb=horizontal-tb \
                                              rl=horizontal-tb rl-tb=horizontal-tb \
                                              tb=vertical-rl   tb-rl=vertical-rl",
                         experimental=True,
                         need_clone=True,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-writing-mode")}

${helpers.single_keyword("direction", "ltr rtl", need_clone=True, animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-direction",
                         needs_conversion=True)}

${helpers.single_keyword("text-orientation",
                         "mixed upright sideways",
                         extra_gecko_aliases="sideways-right=sideways",
                         products="gecko",
                         need_clone=True,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-text-orientation")}

// CSS Color Module Level 4
// https://drafts.csswg.org/css-color/
${helpers.single_keyword("color-adjust",
                         "economy exact", products="gecko",
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-color/#propdef-color-adjust")}

<% image_rendering_custom_consts = { "crisp-edges": "CRISPEDGES",
                                     "-moz-crisp-edges": "CRISPEDGES" } %>
// According to to CSS-IMAGES-3, `optimizespeed` and `optimizequality` are synonyms for `auto`
// And, firefox doesn't support `pixelated` yet (https://bugzilla.mozilla.org/show_bug.cgi?id=856337)
${helpers.single_keyword("image-rendering",
                         "auto",
                         extra_gecko_values="optimizespeed optimizequality -moz-crisp-edges",
                         extra_servo_values="pixelated crisp-edges",
                         custom_consts=image_rendering_custom_consts,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-images/#propdef-image-rendering")}

// Image Orientation
<%helpers:longhand name="image-orientation"
                   products="gecko"
                   animation_value_type="none"
    spec="https://drafts.csswg.org/css-images/#propdef-image-orientation, \
      /// additional values in https://developer.mozilla.org/en-US/docs/Web/CSS/image-orientation">
    use std::fmt;
    use style_traits::ToCss;
    use values::specified::Angle;

    use values::HasViewportPercentage;
    no_viewport_percentage!(SpecifiedValue);

    use std::f32::consts::PI;
    use values::CSSFloat;
    const TWO_PI: CSSFloat = 2.0 * PI;

    #[derive(Clone, PartialEq, Copy, Debug)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
    pub struct SpecifiedValue {
        pub angle: Option<Angle>,
        pub flipped: bool
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if let Some(angle) = self.angle {
                try!(angle.to_css(dest));
                if self.flipped {
                    dest.write_str(" flipped")
                } else {
                    Ok(())
                }
            } else {
                if self.flipped {
                    dest.write_str("flipped")
                } else {
                    dest.write_str("from-image")
                }
            }
        }
    }

    pub mod computed_value {
        use values::computed::Angle;

        #[derive(Clone, PartialEq, Copy, Debug)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum T {
            FromImage,
            AngleWithFlipped(Angle, bool),
        }
    }

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T::AngleWithFlipped(computed::Angle::zero(), false)
    }

    // According to CSS Content Module Level 3:
    // The computed value of the property is calculated by rounding the specified angle
    // to the nearest quarter-turn, rounding away from 0, then moduloing the value by 1 turn.
    #[inline]
    fn normalize_angle(angle: &computed::Angle) -> computed::Angle {
        let radians = angle.radians();
        let rounded_quarter_turns = (4.0 * radians / TWO_PI).round();
        let normalized_quarter_turns = (rounded_quarter_turns % 4.0 + 4.0) % 4.0;
        let normalized_radians = normalized_quarter_turns/4.0 * TWO_PI;
        computed::Angle::from_radians(normalized_radians)
    }

    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, context: &Context) -> computed_value::T {
            if let Some(ref angle) = self.angle {
                let angle = angle.to_computed_value(context);
                let normalized_angle = normalize_angle(&angle);
                computed_value::T::AngleWithFlipped(normalized_angle, self.flipped)
            } else {
                if self.flipped {
                    computed_value::T::AngleWithFlipped(computed::Angle::zero(), true)
                } else {
                    computed_value::T::FromImage
                }
            }
        }

        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> Self {
            match *computed {
                computed_value::T::FromImage => SpecifiedValue { angle: None, flipped: false },
                computed_value::T::AngleWithFlipped(ref angle, flipped) => {
                    SpecifiedValue {
                        angle: Some(Angle::from_computed_value(angle)),
                        flipped: flipped,
                    }
                }
            }
        }
    }

    impl ToCss for computed_value::T {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            match *self {
                computed_value::T::FromImage => dest.write_str("from-image"),
                computed_value::T::AngleWithFlipped(angle, flipped) => {
                    try!(angle.to_css(dest));
                    if flipped {
                        try!(dest.write_str(" flip"));
                    }
                    Ok(())
                },
            }
        }
    }

    // from-image | <angle> | [<angle>? flip]
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        if input.try(|input| input.expect_ident_matching("from-image")).is_ok() {
            // Handle from-image
            Ok(SpecifiedValue { angle: None, flipped: false })
        } else if input.try(|input| input.expect_ident_matching("flip")).is_ok() {
            // Handle flip
            Ok(SpecifiedValue { angle: Some(Angle::zero()), flipped: true })
        } else {
            // Handle <angle> | <angle> flip
            let angle = input.try(|input| Angle::parse(context, input)).ok();
            if angle.is_none() {
                return Err(());
            }

            let flipped = input.try(|input| input.expect_ident_matching("flip")).is_ok();
            Ok(SpecifiedValue { angle: angle, flipped: flipped })
        }
    }
</%helpers:longhand>

// Used in the bottom-up flow construction traversal to avoid constructing flows for
// descendants of nodes with `display: none`.
<%helpers:longhand name="-servo-under-display-none"
                   derived_from="display"
                   products="servo"
                   animation_value_type="none"
                   spec="Nonstandard (internal layout use only)">
    use std::fmt;
    use style_traits::ToCss;
    use values::computed::ComputedValueAsSpecified;
    use values::HasViewportPercentage;

    no_viewport_percentage!(SpecifiedValue);

    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
    pub struct SpecifiedValue(pub bool);

    pub mod computed_value {
        pub type T = super::SpecifiedValue;
    }
    impl ComputedValueAsSpecified for SpecifiedValue {}

    pub fn get_initial_value() -> computed_value::T {
        SpecifiedValue(false)
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, _: &mut W) -> fmt::Result where W: fmt::Write {
            Ok(()) // Internal property
        }
    }

    #[inline]
    pub fn derive_from_display(context: &mut Context) {
        use super::display::computed_value::T as Display;

        if context.style().get_box().clone_display() == Display::none {
            context.mutate_style().mutate_inheritedbox()
                                  .set__servo_under_display_none(SpecifiedValue(true));
        }
    }
</%helpers:longhand>
<commit_msg>stylo: Fix the serialization of image-orientation property. r=heycam<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/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("InheritedBox", inherited=True, gecko_name="Visibility") %>

// TODO: collapse. Well, do tables first.
${helpers.single_keyword("visibility",
                         "visible hidden",
                         extra_gecko_values="collapse",
                         gecko_ffi_name="mVisible",
                         animation_value_type="ComputedValue",
                         spec="https://drafts.csswg.org/css-box/#propdef-visibility")}

// CSS Writing Modes Level 3
// https://drafts.csswg.org/css-writing-modes-3
${helpers.single_keyword("writing-mode",
                         "horizontal-tb vertical-rl vertical-lr",
                         extra_gecko_values="sideways-rl sideways-lr",
                         extra_gecko_aliases="lr=horizontal-tb lr-tb=horizontal-tb \
                                              rl=horizontal-tb rl-tb=horizontal-tb \
                                              tb=vertical-rl   tb-rl=vertical-rl",
                         experimental=True,
                         need_clone=True,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-writing-mode")}

${helpers.single_keyword("direction", "ltr rtl", need_clone=True, animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-direction",
                         needs_conversion=True)}

${helpers.single_keyword("text-orientation",
                         "mixed upright sideways",
                         extra_gecko_aliases="sideways-right=sideways",
                         products="gecko",
                         need_clone=True,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-text-orientation")}

// CSS Color Module Level 4
// https://drafts.csswg.org/css-color/
${helpers.single_keyword("color-adjust",
                         "economy exact", products="gecko",
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-color/#propdef-color-adjust")}

<% image_rendering_custom_consts = { "crisp-edges": "CRISPEDGES",
                                     "-moz-crisp-edges": "CRISPEDGES" } %>
// According to to CSS-IMAGES-3, `optimizespeed` and `optimizequality` are synonyms for `auto`
// And, firefox doesn't support `pixelated` yet (https://bugzilla.mozilla.org/show_bug.cgi?id=856337)
${helpers.single_keyword("image-rendering",
                         "auto",
                         extra_gecko_values="optimizespeed optimizequality -moz-crisp-edges",
                         extra_servo_values="pixelated crisp-edges",
                         custom_consts=image_rendering_custom_consts,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-images/#propdef-image-rendering")}

// Image Orientation
<%helpers:longhand name="image-orientation"
                   products="gecko"
                   animation_value_type="none"
    spec="https://drafts.csswg.org/css-images/#propdef-image-orientation, \
      /// additional values in https://developer.mozilla.org/en-US/docs/Web/CSS/image-orientation">
    use std::fmt;
    use style_traits::ToCss;
    use values::specified::Angle;

    use values::HasViewportPercentage;
    no_viewport_percentage!(SpecifiedValue);

    use std::f32::consts::PI;
    use values::CSSFloat;
    const TWO_PI: CSSFloat = 2.0 * PI;

    #[derive(Clone, PartialEq, Copy, Debug)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
    pub struct SpecifiedValue {
        pub angle: Option<Angle>,
        pub flipped: bool
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if let Some(angle) = self.angle {
                try!(angle.to_css(dest));
                if self.flipped {
                    dest.write_str(" flip")
                } else {
                    Ok(())
                }
            } else {
                if self.flipped {
                    dest.write_str("flip")
                } else {
                    dest.write_str("from-image")
                }
            }
        }
    }

    pub mod computed_value {
        use values::computed::Angle;

        #[derive(Clone, PartialEq, Copy, Debug)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum T {
            FromImage,
            AngleWithFlipped(Angle, bool),
        }
    }

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T::AngleWithFlipped(computed::Angle::zero(), false)
    }

    // According to CSS Content Module Level 3:
    // The computed value of the property is calculated by rounding the specified angle
    // to the nearest quarter-turn, rounding away from 0, then moduloing the value by 1 turn.
    #[inline]
    fn normalize_angle(angle: &computed::Angle) -> computed::Angle {
        let radians = angle.radians();
        let rounded_quarter_turns = (4.0 * radians / TWO_PI).round();
        let normalized_quarter_turns = (rounded_quarter_turns % 4.0 + 4.0) % 4.0;
        let normalized_radians = normalized_quarter_turns/4.0 * TWO_PI;
        computed::Angle::from_radians(normalized_radians)
    }

    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, context: &Context) -> computed_value::T {
            if let Some(ref angle) = self.angle {
                let angle = angle.to_computed_value(context);
                let normalized_angle = normalize_angle(&angle);
                computed_value::T::AngleWithFlipped(normalized_angle, self.flipped)
            } else {
                if self.flipped {
                    computed_value::T::AngleWithFlipped(computed::Angle::zero(), true)
                } else {
                    computed_value::T::FromImage
                }
            }
        }

        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> Self {
            match *computed {
                computed_value::T::FromImage => SpecifiedValue { angle: None, flipped: false },
                computed_value::T::AngleWithFlipped(ref angle, flipped) => {
                    SpecifiedValue {
                        angle: Some(Angle::from_computed_value(angle)),
                        flipped: flipped,
                    }
                }
            }
        }
    }

    impl ToCss for computed_value::T {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            match *self {
                computed_value::T::FromImage => dest.write_str("from-image"),
                computed_value::T::AngleWithFlipped(angle, flipped) => {
                    try!(angle.to_css(dest));
                    if flipped {
                        try!(dest.write_str(" flip"));
                    }
                    Ok(())
                },
            }
        }
    }

    // from-image | <angle> | [<angle>? flip]
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        if input.try(|input| input.expect_ident_matching("from-image")).is_ok() {
            // Handle from-image
            Ok(SpecifiedValue { angle: None, flipped: false })
        } else if input.try(|input| input.expect_ident_matching("flip")).is_ok() {
            // Handle flip
            Ok(SpecifiedValue { angle: Some(Angle::zero()), flipped: true })
        } else {
            // Handle <angle> | <angle> flip
            let angle = input.try(|input| Angle::parse(context, input)).ok();
            if angle.is_none() {
                return Err(());
            }

            let flipped = input.try(|input| input.expect_ident_matching("flip")).is_ok();
            Ok(SpecifiedValue { angle: angle, flipped: flipped })
        }
    }
</%helpers:longhand>

// Used in the bottom-up flow construction traversal to avoid constructing flows for
// descendants of nodes with `display: none`.
<%helpers:longhand name="-servo-under-display-none"
                   derived_from="display"
                   products="servo"
                   animation_value_type="none"
                   spec="Nonstandard (internal layout use only)">
    use std::fmt;
    use style_traits::ToCss;
    use values::computed::ComputedValueAsSpecified;
    use values::HasViewportPercentage;

    no_viewport_percentage!(SpecifiedValue);

    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
    pub struct SpecifiedValue(pub bool);

    pub mod computed_value {
        pub type T = super::SpecifiedValue;
    }
    impl ComputedValueAsSpecified for SpecifiedValue {}

    pub fn get_initial_value() -> computed_value::T {
        SpecifiedValue(false)
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, _: &mut W) -> fmt::Result where W: fmt::Write {
            Ok(()) // Internal property
        }
    }

    #[inline]
    pub fn derive_from_display(context: &mut Context) {
        use super::display::computed_value::T as Display;

        if context.style().get_box().clone_display() == Display::none {
            context.mutate_style().mutate_inheritedbox()
                                  .set__servo_under_display_none(SpecifiedValue(true));
        }
    }
</%helpers:longhand>
<|endoftext|>


<commit_before>use expression::Expression;
use query_builder::AsQuery;
use query_source::QuerySource;

/// Sets the order clause of a query. If there was already a order clause, it
/// will be overridden. The expression passed to `order` must actually be valid
/// for the query. See also:
/// [`.desc()`](../../expression/expression_methods/global_expression_methods/trait.ExpressionMethods.html#method.desc)
/// and [`.asc()`](../../expression/expression_methods/global_expression_methods/trait.ExpressionMethods.html#method.asc)
///
/// This is automatically implemented for the various query builder types.
pub trait OrderDsl<Expr: Expression>: AsQuery {
    type Output: AsQuery<SqlType=Self::SqlType>;

    fn order(self, expr: Expr) -> Self::Output;
}

impl<T, Expr, ST> OrderDsl<Expr> for T where
    Expr: Expression,
    T: QuerySource + AsQuery<SqlType=ST>,
    T::Query: OrderDsl<Expr, SqlType=ST>,
{
    type Output = <T::Query as OrderDsl<Expr>>::Output;

    fn order(self, expr: Expr) -> Self::Output {
        self.as_query().order(expr)
    }
}
<commit_msg>Mention that tuples can be passed to order<commit_after>use expression::Expression;
use query_builder::AsQuery;
use query_source::QuerySource;

/// Sets the order clause of a query. If there was already a order clause, it
/// will be overridden. The expression passed to `order` must actually be valid
/// for the query. See also:
/// [`.desc()`](../../expression/expression_methods/global_expression_methods/trait.ExpressionMethods.html#method.desc)
/// and [`.asc()`](../../expression/expression_methods/global_expression_methods/trait.ExpressionMethods.html#method.asc)
///
/// Ordering by multiple columns can be achieved by passing a tuple of those
/// columns.
///
/// This is automatically implemented for the various query builder types.
pub trait OrderDsl<Expr: Expression>: AsQuery {
    type Output: AsQuery<SqlType=Self::SqlType>;

    fn order(self, expr: Expr) -> Self::Output;
}

impl<T, Expr, ST> OrderDsl<Expr> for T where
    Expr: Expression,
    T: QuerySource + AsQuery<SqlType=ST>,
    T::Query: OrderDsl<Expr, SqlType=ST>,
{
    type Output = <T::Query as OrderDsl<Expr>>::Output;

    fn order(self, expr: Expr) -> Self::Output {
        self.as_query().order(expr)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::proto::{
    secret_service::{ErrorCode, GenerateKeyRequest, PublicKeyRequest},
    secret_service_grpc::SecretServiceClient,
};
use config::config::{NodeConfig, NodeConfigHelpers};
use debug_interface::node_debug_helpers::{check_node_up, create_debug_client};
use grpcio::{ChannelBuilder, EnvBuilder};
use std::{sync::Arc, thread};

use crate::{
    proto::secret_service::KeyType, secret_service_client::ConsensusKeyManager,
    secret_service_node::SecretServiceNode,
};
use crypto::hash::HashValue;
use logger::prelude::*;
// use crate::crypto_wrappers::GenericSignature;
use crypto::traits::Signature;

/////////////////////////////////////////////////////////////////////////////////////
// These tests check interoperability of key_generation,                           //
// key_retrieval and signing for crate::secret_service_server::SecretServiceServer //
/////////////////////////////////////////////////////////////////////////////////////

#[test]
fn create_secret_service_node() {
    let node_config = NodeConfigHelpers::get_single_node_test_config(true);
    let _secret_service_node = SecretServiceNode::new(node_config);
}

fn create_client(public_port: u16) -> SecretServiceClient {
    let node_connection_str = format!("localhost:{}", public_port);
    let env = Arc::new(EnvBuilder::new().build());
    let ch = ChannelBuilder::new(env).connect(&node_connection_str);
    SecretServiceClient::new(ch)
}

fn create_secret_service_node_and_client(node_config: NodeConfig) -> SecretServiceClient {
    let public_port = node_config.secret_service.secret_service_port;
    let debug_port = node_config.debug_interface.secret_service_node_debug_port;

    thread::spawn(move || {
        let secret_service_node = SecretServiceNode::new(node_config);
        secret_service_node.run().unwrap();
        info!("SecretService node stopped");
    });

    let debug_client = create_debug_client(debug_port);
    check_node_up(&debug_client);

    create_client(public_port)
}

// Testing higher level interface //
#[test]
fn test_generate_consensus_key() {
    let node_config = NodeConfigHelpers::get_single_node_test_config(true);
    let client = create_secret_service_node_and_client(node_config.clone());

    let key_manager = ConsensusKeyManager::new(Arc::new(client)).unwrap();
    let public_key = key_manager.get_consensus_public_key().unwrap();
    // let message_hash = b"consensus test message".digest(STANDARD_DIGESTER.get());
    let message_hash = HashValue::random();
    let signature = key_manager.sign_consensus_message(&message_hash).unwrap();
    // check that the signature verifies
    assert!(
        signature.verify(&message_hash, &public_key).is_ok(),
        "Correct signature does not verify"
    );
}

#[test]
fn test_generate_key() {
    let node_config = NodeConfigHelpers::get_single_node_test_config(true);
    let client = create_secret_service_node_and_client(node_config.clone());

    // create request to generate new key
    let mut gen_req: GenerateKeyRequest = GenerateKeyRequest::new();
    gen_req.set_spec(KeyType::Ed25519);

    let result = client.generate_key(&gen_req);
    if result.is_ok() {
        let response = result.ok().unwrap();
        let is_successful = response.get_code() == ErrorCode::Success;
        assert!(is_successful);
    } else {
        panic!("key generation failed: {}", result.err().unwrap());
    }
}

#[test]
fn test_generate_and_retrieve_key() {
    let node_config = NodeConfigHelpers::get_single_node_test_config(true);
    let client = create_secret_service_node_and_client(node_config.clone());

    // create request to generate new key
    let mut gen_req: GenerateKeyRequest = GenerateKeyRequest::new();
    gen_req.set_spec(KeyType::Ed25519);

    let result = client.generate_key(&gen_req);
    if result.is_err() {
        panic!("key generation failed: {}", result.err().unwrap());
    }

    let response = result.ok().unwrap();
    let is_successful = response.get_code() == ErrorCode::Success;
    assert!(is_successful);
    let keyid = response.get_key_id();

    // assert_eq!(keyid, [230, 70, 121, 164, 224, 224, 49, 236, 222, 129, 71, 209, 108, 208, 39,
    // 161, 6, 166, 100, 236, 85, 0, 83, 224, 28, 229, 132, 230, 86, 31, 198, 235]);

    // existing key can be obtained
    let mut pk_req: PublicKeyRequest = PublicKeyRequest::new();
    pk_req.set_key_id(keyid.to_vec());

    let result = client.get_public_key(&pk_req);
    if result.is_err() {
        panic!("public key retrieval failed: {}", result.err().unwrap());
    }
    let response = result.ok().unwrap();
    let is_successful = response.get_code() == ErrorCode::Success;
    assert!(is_successful);
    let _result = response.get_public_key();

    // invalid length keyid argument returns an error
    let mut pk_req: PublicKeyRequest = PublicKeyRequest::new();
    pk_req.set_key_id([0, 1, 2, 4].to_vec());

    let result = client.get_public_key(&pk_req);
    if result.is_err() {
        panic!("public key retrieval failed: {}", result.err().unwrap());
    }
    let response = result.ok().unwrap();
    let is_successful = response.get_code() == ErrorCode::WrongLength;
    assert!(is_successful);

    // obtaining non-existing key returns an error
    let mut pk_req: PublicKeyRequest = PublicKeyRequest::new();
    pk_req.set_key_id([255; HashValue::LENGTH].to_vec());

    let result = client.get_public_key(&pk_req);
    if result.is_err() {
        panic!("public key retrieval failed: {}", result.err().unwrap());
    }
    let response = result.ok().unwrap();
    let is_successful = response.get_code() == ErrorCode::KeyIdNotFound;
    assert!(is_successful);
}
<commit_msg>Rewrite an instance of `if let OK(x) = result`<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::proto::{
    secret_service::{ErrorCode, GenerateKeyRequest, PublicKeyRequest},
    secret_service_grpc::SecretServiceClient,
};
use config::config::{NodeConfig, NodeConfigHelpers};
use debug_interface::node_debug_helpers::{check_node_up, create_debug_client};
use grpcio::{ChannelBuilder, EnvBuilder};
use std::{sync::Arc, thread};

use crate::{
    proto::secret_service::KeyType, secret_service_client::ConsensusKeyManager,
    secret_service_node::SecretServiceNode,
};
use crypto::hash::HashValue;
use logger::prelude::*;
// use crate::crypto_wrappers::GenericSignature;
use crypto::traits::Signature;

/////////////////////////////////////////////////////////////////////////////////////
// These tests check interoperability of key_generation,                           //
// key_retrieval and signing for crate::secret_service_server::SecretServiceServer //
/////////////////////////////////////////////////////////////////////////////////////

#[test]
fn create_secret_service_node() {
    let node_config = NodeConfigHelpers::get_single_node_test_config(true);
    let _secret_service_node = SecretServiceNode::new(node_config);
}

fn create_client(public_port: u16) -> SecretServiceClient {
    let node_connection_str = format!("localhost:{}", public_port);
    let env = Arc::new(EnvBuilder::new().build());
    let ch = ChannelBuilder::new(env).connect(&node_connection_str);
    SecretServiceClient::new(ch)
}

fn create_secret_service_node_and_client(node_config: NodeConfig) -> SecretServiceClient {
    let public_port = node_config.secret_service.secret_service_port;
    let debug_port = node_config.debug_interface.secret_service_node_debug_port;

    thread::spawn(move || {
        let secret_service_node = SecretServiceNode::new(node_config);
        secret_service_node.run().unwrap();
        info!("SecretService node stopped");
    });

    let debug_client = create_debug_client(debug_port);
    check_node_up(&debug_client);

    create_client(public_port)
}

// Testing higher level interface //
#[test]
fn test_generate_consensus_key() {
    let node_config = NodeConfigHelpers::get_single_node_test_config(true);
    let client = create_secret_service_node_and_client(node_config.clone());

    let key_manager = ConsensusKeyManager::new(Arc::new(client)).unwrap();
    let public_key = key_manager.get_consensus_public_key().unwrap();
    // let message_hash = b"consensus test message".digest(STANDARD_DIGESTER.get());
    let message_hash = HashValue::random();
    let signature = key_manager.sign_consensus_message(&message_hash).unwrap();
    // check that the signature verifies
    assert!(
        signature.verify(&message_hash, &public_key).is_ok(),
        "Correct signature does not verify"
    );
}

#[test]
fn test_generate_key() {
    let node_config = NodeConfigHelpers::get_single_node_test_config(true);
    let client = create_secret_service_node_and_client(node_config.clone());

    // create request to generate new key
    let mut gen_req: GenerateKeyRequest = GenerateKeyRequest::new();
    gen_req.set_spec(KeyType::Ed25519);

    let result = client.generate_key(&gen_req);
    if let Ok(response) = result {
        let is_successful = response.get_code() == ErrorCode::Success;
        assert!(is_successful);
    } else {
        panic!("key generation failed: {}", result.err().unwrap());
    }
}

#[test]
fn test_generate_and_retrieve_key() {
    let node_config = NodeConfigHelpers::get_single_node_test_config(true);
    let client = create_secret_service_node_and_client(node_config.clone());

    // create request to generate new key
    let mut gen_req: GenerateKeyRequest = GenerateKeyRequest::new();
    gen_req.set_spec(KeyType::Ed25519);

    let result = client.generate_key(&gen_req);
    if result.is_err() {
        panic!("key generation failed: {}", result.err().unwrap());
    }

    let response = result.ok().unwrap();
    let is_successful = response.get_code() == ErrorCode::Success;
    assert!(is_successful);
    let keyid = response.get_key_id();

    // assert_eq!(keyid, [230, 70, 121, 164, 224, 224, 49, 236, 222, 129, 71, 209, 108, 208, 39,
    // 161, 6, 166, 100, 236, 85, 0, 83, 224, 28, 229, 132, 230, 86, 31, 198, 235]);

    // existing key can be obtained
    let mut pk_req: PublicKeyRequest = PublicKeyRequest::new();
    pk_req.set_key_id(keyid.to_vec());

    let result = client.get_public_key(&pk_req);
    if result.is_err() {
        panic!("public key retrieval failed: {}", result.err().unwrap());
    }
    let response = result.ok().unwrap();
    let is_successful = response.get_code() == ErrorCode::Success;
    assert!(is_successful);
    let _result = response.get_public_key();

    // invalid length keyid argument returns an error
    let mut pk_req: PublicKeyRequest = PublicKeyRequest::new();
    pk_req.set_key_id([0, 1, 2, 4].to_vec());

    let result = client.get_public_key(&pk_req);
    if result.is_err() {
        panic!("public key retrieval failed: {}", result.err().unwrap());
    }
    let response = result.ok().unwrap();
    let is_successful = response.get_code() == ErrorCode::WrongLength;
    assert!(is_successful);

    // obtaining non-existing key returns an error
    let mut pk_req: PublicKeyRequest = PublicKeyRequest::new();
    pk_req.set_key_id([255; HashValue::LENGTH].to_vec());

    let result = client.get_public_key(&pk_req);
    if result.is_err() {
        panic!("public key retrieval failed: {}", result.err().unwrap());
    }
    let response = result.ok().unwrap();
    let is_successful = response.get_code() == ErrorCode::KeyIdNotFound;
    assert!(is_successful);
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Runs hardware devices in child processes.

use std::ffi::CString;
use std::time::Duration;

use base::{error, AsRawDescriptor, RawDescriptor, Tube, TubeError};
use libc::{self, pid_t};
use minijail::{self, Minijail};
use remain::sorted;
use serde::{Deserialize, Serialize};
use thiserror::Error;

use crate::bus::ConfigWriteResult;
use crate::pci::{CrosvmDeviceId, PciAddress};
use crate::{BusAccessInfo, BusDevice, BusRange, BusType, DeviceId};

/// Errors for proxy devices.
#[sorted]
#[derive(Error, Debug)]
pub enum Error {
    #[error("Failed to fork jail process: {0}")]
    ForkingJail(minijail::Error),
    #[error("Failed to configure tube: {0}")]
    Tube(TubeError),
}

pub type Result<T> = std::result::Result<T, Error>;

const SOCKET_TIMEOUT_MS: u64 = 2000;

#[derive(Debug, Serialize, Deserialize)]
enum Command {
    Read {
        len: u32,
        info: BusAccessInfo,
    },
    Write {
        len: u32,
        info: BusAccessInfo,
        data: [u8; 8],
    },
    ReadConfig(u32),
    WriteConfig {
        reg_idx: u32,
        offset: u32,
        len: u32,
        data: [u8; 4],
    },
    ReadVirtualConfig(u32),
    WriteVirtualConfig {
        reg_idx: u32,
        value: u32,
    },
    Shutdown,
    GetRanges,
}
#[derive(Debug, Serialize, Deserialize)]
enum CommandResult {
    Ok,
    ReadResult([u8; 8]),
    ReadConfigResult(u32),
    WriteConfigResult {
        mmio_remove: Vec<BusRange>,
        mmio_add: Vec<BusRange>,
        io_remove: Vec<BusRange>,
        io_add: Vec<BusRange>,
        removed_pci_devices: Vec<PciAddress>,
    },
    ReadVirtualConfigResult(u32),
    GetRangesResult(Vec<(BusRange, BusType)>),
}

fn child_proc<D: BusDevice>(tube: Tube, device: &mut D) {
    let mut running = true;

    while running {
        let cmd = match tube.recv() {
            Ok(cmd) => cmd,
            Err(err) => {
                error!("child device process failed recv: {}", err);
                break;
            }
        };

        let res = match cmd {
            Command::Read { len, info } => {
                let mut buffer = [0u8; 8];
                device.read(info, &mut buffer[0..len as usize]);
                tube.send(&CommandResult::ReadResult(buffer))
            }
            Command::Write { len, info, data } => {
                let len = len as usize;
                device.write(info, &data[0..len]);
                // Command::Write does not have a result.
                Ok(())
            }
            Command::ReadConfig(idx) => {
                let val = device.config_register_read(idx as usize);
                tube.send(&CommandResult::ReadConfigResult(val))
            }
            Command::WriteConfig {
                reg_idx,
                offset,
                len,
                data,
            } => {
                let len = len as usize;
                let res =
                    device.config_register_write(reg_idx as usize, offset as u64, &data[0..len]);
                tube.send(&CommandResult::WriteConfigResult {
                    mmio_remove: res.mmio_remove,
                    mmio_add: res.mmio_add,
                    io_remove: res.io_remove,
                    io_add: res.io_add,
                    removed_pci_devices: res.removed_pci_devices,
                })
            }
            Command::ReadVirtualConfig(idx) => {
                let val = device.virtual_config_register_read(idx as usize);
                tube.send(&CommandResult::ReadVirtualConfigResult(val))
            }
            Command::WriteVirtualConfig { reg_idx, value } => {
                device.virtual_config_register_write(reg_idx as usize, value);
                // Command::WriteVirtualConfig does not have a result.
                Ok(())
            }
            Command::Shutdown => {
                running = false;
                tube.send(&CommandResult::Ok)
            }
            Command::GetRanges => {
                let ranges = device.get_ranges();
                tube.send(&CommandResult::GetRangesResult(ranges))
            }
        };
        if let Err(e) = res {
            error!("child device process failed send: {}", e);
        }
    }
}

/// Wraps an inner `BusDevice` that is run inside a child process via fork.
///
/// Because forks are very unfriendly to destructors and all memory mappings and file descriptors
/// are inherited, this should be used as early as possible in the main process.
pub struct ProxyDevice {
    tube: Tube,
    pid: pid_t,
    debug_label: String,
}

impl ProxyDevice {
    /// Takes the given device and isolates it into another process via fork before returning.
    ///
    /// The forked process will automatically be terminated when this is dropped, so be sure to keep
    /// a reference.
    ///
    /// # Arguments
    /// * `device` - The device to isolate to another process.
    /// * `jail` - The jail to use for isolating the given device.
    /// * `keep_rds` - File descriptors that will be kept open in the child.
    pub fn new<D: BusDevice>(
        mut device: D,
        jail: &Minijail,
        mut keep_rds: Vec<RawDescriptor>,
    ) -> Result<ProxyDevice> {
        let debug_label = device.debug_label();
        let (child_tube, parent_tube) = Tube::pair().map_err(Error::Tube)?;

        keep_rds.push(child_tube.as_raw_descriptor());

        // Deduplicate the FDs since minijail expects this.
        keep_rds.sort_unstable();
        keep_rds.dedup();

        // Forking here is safe as long as the program is still single threaded.
        let pid = unsafe {
            match jail.fork(Some(&keep_rds)).map_err(Error::ForkingJail)? {
                0 => {
                    let max_len = 15; // pthread_setname_np() limit on Linux
                    let debug_label_trimmed =
                        &debug_label.as_bytes()[..std::cmp::min(max_len, debug_label.len())];
                    let thread_name = CString::new(debug_label_trimmed).unwrap();
                    let _ = libc::pthread_setname_np(libc::pthread_self(), thread_name.as_ptr());
                    device.on_sandboxed();
                    child_proc(child_tube, &mut device);

                    // We're explicitly not using std::process::exit here to avoid the cleanup of
                    // stdout/stderr globals. This can cause cascading panics and SIGILL if a worker
                    // thread attempts to log to stderr after at_exit handlers have been run.
                    // TODO(crbug.com/992494): Remove this once device shutdown ordering is clearly
                    // defined.
                    //
                    // exit() is trivially safe.
                    // ! Never returns
                    libc::exit(0);
                }
                p => p,
            }
        };

        parent_tube
            .set_send_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
            .map_err(Error::Tube)?;
        parent_tube
            .set_recv_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
            .map_err(Error::Tube)?;
        Ok(ProxyDevice {
            tube: parent_tube,
            pid,
            debug_label,
        })
    }

    pub fn pid(&self) -> pid_t {
        self.pid
    }

    /// Send a command that does not expect a response from the child device process.
    fn send_no_result(&self, cmd: &Command) {
        let res = self.tube.send(cmd);
        if let Err(e) = res {
            error!(
                "failed write to child device process {}: {}",
                self.debug_label, e,
            );
        }
    }

    /// Send a command and read its response from the child device process.
    fn sync_send(&self, cmd: &Command) -> Option<CommandResult> {
        self.send_no_result(cmd);
        match self.tube.recv() {
            Err(e) => {
                error!(
                    "failed to read result of {:?} from child device process {}: {}",
                    cmd, self.debug_label, e,
                );
                None
            }
            Ok(r) => Some(r),
        }
    }
}

impl BusDevice for ProxyDevice {
    fn device_id(&self) -> DeviceId {
        CrosvmDeviceId::ProxyDevice.into()
    }

    fn debug_label(&self) -> String {
        self.debug_label.clone()
    }

    fn config_register_write(
        &mut self,
        reg_idx: usize,
        offset: u64,
        data: &[u8],
    ) -> ConfigWriteResult {
        let len = data.len() as u32;
        let mut buffer = [0u8; 4];
        buffer[0..data.len()].clone_from_slice(data);
        let reg_idx = reg_idx as u32;
        let offset = offset as u32;
        if let Some(CommandResult::WriteConfigResult {
            mmio_remove,
            mmio_add,
            io_remove,
            io_add,
            removed_pci_devices,
        }) = self.sync_send(&Command::WriteConfig {
            reg_idx,
            offset,
            len,
            data: buffer,
        }) {
            ConfigWriteResult {
                mmio_remove,
                mmio_add,
                io_remove,
                io_add,
                removed_pci_devices,
            }
        } else {
            Default::default()
        }
    }

    fn config_register_read(&self, reg_idx: usize) -> u32 {
        let res = self.sync_send(&Command::ReadConfig(reg_idx as u32));
        if let Some(CommandResult::ReadConfigResult(val)) = res {
            val
        } else {
            0
        }
    }

    fn virtual_config_register_write(&mut self, reg_idx: usize, value: u32) {
        let reg_idx = reg_idx as u32;
        self.send_no_result(&Command::WriteVirtualConfig { reg_idx, value });
    }

    fn virtual_config_register_read(&self, reg_idx: usize) -> u32 {
        let res = self.sync_send(&Command::ReadVirtualConfig(reg_idx as u32));
        if let Some(CommandResult::ReadVirtualConfigResult(val)) = res {
            val
        } else {
            0
        }
    }

    fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
        let len = data.len() as u32;
        if let Some(CommandResult::ReadResult(buffer)) =
            self.sync_send(&Command::Read { len, info })
        {
            let len = data.len();
            data.clone_from_slice(&buffer[0..len]);
        }
    }

    fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
        let mut buffer = [0u8; 8];
        let len = data.len() as u32;
        buffer[0..data.len()].clone_from_slice(data);
        self.send_no_result(&Command::Write {
            len,
            info,
            data: buffer,
        });
    }

    fn get_ranges(&self) -> Vec<(BusRange, BusType)> {
        if let Some(CommandResult::GetRangesResult(ranges)) = self.sync_send(&Command::GetRanges) {
            ranges
        } else {
            Default::default()
        }
    }
}

impl Drop for ProxyDevice {
    fn drop(&mut self) {
        self.sync_send(&Command::Shutdown);
    }
}

/// Note: These tests must be run with --test-threads=1 to allow minijail to fork
/// the process.
#[cfg(test)]
mod tests {
    use crate::pci::PciId;

    use super::*;

    /// A simple test echo device that outputs the same u8 that was written to it.
    struct EchoDevice {
        data: u8,
        config: u8,
    }
    impl EchoDevice {
        fn new() -> EchoDevice {
            EchoDevice { data: 0, config: 0 }
        }
    }
    impl BusDevice for EchoDevice {
        fn device_id(&self) -> DeviceId {
            PciId::new(0, 0).into()
        }

        fn debug_label(&self) -> String {
            "EchoDevice".to_owned()
        }

        fn write(&mut self, _info: BusAccessInfo, data: &[u8]) {
            assert!(data.len() == 1);
            self.data = data[0];
        }

        fn read(&mut self, _info: BusAccessInfo, data: &mut [u8]) {
            assert!(data.len() == 1);
            data[0] = self.data;
        }

        fn config_register_write(
            &mut self,
            _reg_idx: usize,
            _offset: u64,
            data: &[u8],
        ) -> ConfigWriteResult {
            let result = ConfigWriteResult {
                ..Default::default()
            };
            assert!(data.len() == 1);
            self.config = data[0];
            result
        }

        fn config_register_read(&self, _reg_idx: usize) -> u32 {
            self.config as u32
        }
    }

    fn new_proxied_echo_device() -> ProxyDevice {
        let device = EchoDevice::new();
        let keep_fds: Vec<RawDescriptor> = Vec::new();
        let minijail = Minijail::new().unwrap();
        ProxyDevice::new(device, &minijail, keep_fds).unwrap()
    }

    // TODO(b/173833661): Find a way to ensure these tests are run single-threaded.
    #[test]
    #[ignore]
    fn test_debug_label() {
        let proxy_device = new_proxied_echo_device();
        assert_eq!(proxy_device.debug_label(), "EchoDevice");
    }

    #[test]
    #[ignore]
    fn test_proxied_read_write() {
        let mut proxy_device = new_proxied_echo_device();
        let address = BusAccessInfo {
            offset: 0,
            address: 0,
            id: 0,
        };
        proxy_device.write(address, &[42]);
        let mut read_buffer = [0];
        proxy_device.read(address, &mut read_buffer);
        assert_eq!(read_buffer, [42]);
    }

    #[test]
    #[ignore]
    fn test_proxied_config() {
        let mut proxy_device = new_proxied_echo_device();
        proxy_device.config_register_write(0, 0, &[42]);
        assert_eq!(proxy_device.config_register_read(0), 42);
    }
}
<commit_msg>devices: Narrower unsafe blocks.<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Runs hardware devices in child processes.

use std::ffi::CString;
use std::time::Duration;

use base::{error, AsRawDescriptor, RawDescriptor, Tube, TubeError};
use libc::{self, pid_t};
use minijail::{self, Minijail};
use remain::sorted;
use serde::{Deserialize, Serialize};
use thiserror::Error;

use crate::bus::ConfigWriteResult;
use crate::pci::{CrosvmDeviceId, PciAddress};
use crate::{BusAccessInfo, BusDevice, BusRange, BusType, DeviceId};

/// Errors for proxy devices.
#[sorted]
#[derive(Error, Debug)]
pub enum Error {
    #[error("Failed to fork jail process: {0}")]
    ForkingJail(minijail::Error),
    #[error("Failed to configure tube: {0}")]
    Tube(TubeError),
}

pub type Result<T> = std::result::Result<T, Error>;

const SOCKET_TIMEOUT_MS: u64 = 2000;

#[derive(Debug, Serialize, Deserialize)]
enum Command {
    Read {
        len: u32,
        info: BusAccessInfo,
    },
    Write {
        len: u32,
        info: BusAccessInfo,
        data: [u8; 8],
    },
    ReadConfig(u32),
    WriteConfig {
        reg_idx: u32,
        offset: u32,
        len: u32,
        data: [u8; 4],
    },
    ReadVirtualConfig(u32),
    WriteVirtualConfig {
        reg_idx: u32,
        value: u32,
    },
    Shutdown,
    GetRanges,
}
#[derive(Debug, Serialize, Deserialize)]
enum CommandResult {
    Ok,
    ReadResult([u8; 8]),
    ReadConfigResult(u32),
    WriteConfigResult {
        mmio_remove: Vec<BusRange>,
        mmio_add: Vec<BusRange>,
        io_remove: Vec<BusRange>,
        io_add: Vec<BusRange>,
        removed_pci_devices: Vec<PciAddress>,
    },
    ReadVirtualConfigResult(u32),
    GetRangesResult(Vec<(BusRange, BusType)>),
}

fn child_proc<D: BusDevice>(tube: Tube, device: &mut D) {
    let mut running = true;

    while running {
        let cmd = match tube.recv() {
            Ok(cmd) => cmd,
            Err(err) => {
                error!("child device process failed recv: {}", err);
                break;
            }
        };

        let res = match cmd {
            Command::Read { len, info } => {
                let mut buffer = [0u8; 8];
                device.read(info, &mut buffer[0..len as usize]);
                tube.send(&CommandResult::ReadResult(buffer))
            }
            Command::Write { len, info, data } => {
                let len = len as usize;
                device.write(info, &data[0..len]);
                // Command::Write does not have a result.
                Ok(())
            }
            Command::ReadConfig(idx) => {
                let val = device.config_register_read(idx as usize);
                tube.send(&CommandResult::ReadConfigResult(val))
            }
            Command::WriteConfig {
                reg_idx,
                offset,
                len,
                data,
            } => {
                let len = len as usize;
                let res =
                    device.config_register_write(reg_idx as usize, offset as u64, &data[0..len]);
                tube.send(&CommandResult::WriteConfigResult {
                    mmio_remove: res.mmio_remove,
                    mmio_add: res.mmio_add,
                    io_remove: res.io_remove,
                    io_add: res.io_add,
                    removed_pci_devices: res.removed_pci_devices,
                })
            }
            Command::ReadVirtualConfig(idx) => {
                let val = device.virtual_config_register_read(idx as usize);
                tube.send(&CommandResult::ReadVirtualConfigResult(val))
            }
            Command::WriteVirtualConfig { reg_idx, value } => {
                device.virtual_config_register_write(reg_idx as usize, value);
                // Command::WriteVirtualConfig does not have a result.
                Ok(())
            }
            Command::Shutdown => {
                running = false;
                tube.send(&CommandResult::Ok)
            }
            Command::GetRanges => {
                let ranges = device.get_ranges();
                tube.send(&CommandResult::GetRangesResult(ranges))
            }
        };
        if let Err(e) = res {
            error!("child device process failed send: {}", e);
        }
    }
}

/// Wraps an inner `BusDevice` that is run inside a child process via fork.
///
/// Because forks are very unfriendly to destructors and all memory mappings and file descriptors
/// are inherited, this should be used as early as possible in the main process.
pub struct ProxyDevice {
    tube: Tube,
    pid: pid_t,
    debug_label: String,
}

impl ProxyDevice {
    /// Takes the given device and isolates it into another process via fork before returning.
    ///
    /// The forked process will automatically be terminated when this is dropped, so be sure to keep
    /// a reference.
    ///
    /// # Arguments
    /// * `device` - The device to isolate to another process.
    /// * `jail` - The jail to use for isolating the given device.
    /// * `keep_rds` - File descriptors that will be kept open in the child.
    pub fn new<D: BusDevice>(
        mut device: D,
        jail: &Minijail,
        mut keep_rds: Vec<RawDescriptor>,
    ) -> Result<ProxyDevice> {
        let debug_label = device.debug_label();
        let (child_tube, parent_tube) = Tube::pair().map_err(Error::Tube)?;

        keep_rds.push(child_tube.as_raw_descriptor());

        // Deduplicate the FDs since minijail expects this.
        keep_rds.sort_unstable();
        keep_rds.dedup();

        // Forking here is safe as long as the program is still single threaded.
        let pid = match unsafe { jail.fork(Some(&keep_rds)) }.map_err(Error::ForkingJail)? {
            0 => {
                let max_len = 15; // pthread_setname_np() limit on Linux
                let debug_label_trimmed =
                    &debug_label.as_bytes()[..std::cmp::min(max_len, debug_label.len())];
                let thread_name = CString::new(debug_label_trimmed).unwrap();
                // thread_name is a valid pointer and setting name of this thread should be safe.
                let _ =
                    unsafe { libc::pthread_setname_np(libc::pthread_self(), thread_name.as_ptr()) };
                device.on_sandboxed();
                child_proc(child_tube, &mut device);

                // We're explicitly not using std::process::exit here to avoid the cleanup of
                // stdout/stderr globals. This can cause cascading panics and SIGILL if a worker
                // thread attempts to log to stderr after at_exit handlers have been run.
                // TODO(crbug.com/992494): Remove this once device shutdown ordering is clearly
                // defined.
                //
                // exit() is trivially safe.
                // ! Never returns
                unsafe { libc::exit(0) };
            }
            p => p,
        };

        parent_tube
            .set_send_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
            .map_err(Error::Tube)?;
        parent_tube
            .set_recv_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
            .map_err(Error::Tube)?;
        Ok(ProxyDevice {
            tube: parent_tube,
            pid,
            debug_label,
        })
    }

    pub fn pid(&self) -> pid_t {
        self.pid
    }

    /// Send a command that does not expect a response from the child device process.
    fn send_no_result(&self, cmd: &Command) {
        let res = self.tube.send(cmd);
        if let Err(e) = res {
            error!(
                "failed write to child device process {}: {}",
                self.debug_label, e,
            );
        }
    }

    /// Send a command and read its response from the child device process.
    fn sync_send(&self, cmd: &Command) -> Option<CommandResult> {
        self.send_no_result(cmd);
        match self.tube.recv() {
            Err(e) => {
                error!(
                    "failed to read result of {:?} from child device process {}: {}",
                    cmd, self.debug_label, e,
                );
                None
            }
            Ok(r) => Some(r),
        }
    }
}

impl BusDevice for ProxyDevice {
    fn device_id(&self) -> DeviceId {
        CrosvmDeviceId::ProxyDevice.into()
    }

    fn debug_label(&self) -> String {
        self.debug_label.clone()
    }

    fn config_register_write(
        &mut self,
        reg_idx: usize,
        offset: u64,
        data: &[u8],
    ) -> ConfigWriteResult {
        let len = data.len() as u32;
        let mut buffer = [0u8; 4];
        buffer[0..data.len()].clone_from_slice(data);
        let reg_idx = reg_idx as u32;
        let offset = offset as u32;
        if let Some(CommandResult::WriteConfigResult {
            mmio_remove,
            mmio_add,
            io_remove,
            io_add,
            removed_pci_devices,
        }) = self.sync_send(&Command::WriteConfig {
            reg_idx,
            offset,
            len,
            data: buffer,
        }) {
            ConfigWriteResult {
                mmio_remove,
                mmio_add,
                io_remove,
                io_add,
                removed_pci_devices,
            }
        } else {
            Default::default()
        }
    }

    fn config_register_read(&self, reg_idx: usize) -> u32 {
        let res = self.sync_send(&Command::ReadConfig(reg_idx as u32));
        if let Some(CommandResult::ReadConfigResult(val)) = res {
            val
        } else {
            0
        }
    }

    fn virtual_config_register_write(&mut self, reg_idx: usize, value: u32) {
        let reg_idx = reg_idx as u32;
        self.send_no_result(&Command::WriteVirtualConfig { reg_idx, value });
    }

    fn virtual_config_register_read(&self, reg_idx: usize) -> u32 {
        let res = self.sync_send(&Command::ReadVirtualConfig(reg_idx as u32));
        if let Some(CommandResult::ReadVirtualConfigResult(val)) = res {
            val
        } else {
            0
        }
    }

    fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
        let len = data.len() as u32;
        if let Some(CommandResult::ReadResult(buffer)) =
            self.sync_send(&Command::Read { len, info })
        {
            let len = data.len();
            data.clone_from_slice(&buffer[0..len]);
        }
    }

    fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
        let mut buffer = [0u8; 8];
        let len = data.len() as u32;
        buffer[0..data.len()].clone_from_slice(data);
        self.send_no_result(&Command::Write {
            len,
            info,
            data: buffer,
        });
    }

    fn get_ranges(&self) -> Vec<(BusRange, BusType)> {
        if let Some(CommandResult::GetRangesResult(ranges)) = self.sync_send(&Command::GetRanges) {
            ranges
        } else {
            Default::default()
        }
    }
}

impl Drop for ProxyDevice {
    fn drop(&mut self) {
        self.sync_send(&Command::Shutdown);
    }
}

/// Note: These tests must be run with --test-threads=1 to allow minijail to fork
/// the process.
#[cfg(test)]
mod tests {
    use crate::pci::PciId;

    use super::*;

    /// A simple test echo device that outputs the same u8 that was written to it.
    struct EchoDevice {
        data: u8,
        config: u8,
    }
    impl EchoDevice {
        fn new() -> EchoDevice {
            EchoDevice { data: 0, config: 0 }
        }
    }
    impl BusDevice for EchoDevice {
        fn device_id(&self) -> DeviceId {
            PciId::new(0, 0).into()
        }

        fn debug_label(&self) -> String {
            "EchoDevice".to_owned()
        }

        fn write(&mut self, _info: BusAccessInfo, data: &[u8]) {
            assert!(data.len() == 1);
            self.data = data[0];
        }

        fn read(&mut self, _info: BusAccessInfo, data: &mut [u8]) {
            assert!(data.len() == 1);
            data[0] = self.data;
        }

        fn config_register_write(
            &mut self,
            _reg_idx: usize,
            _offset: u64,
            data: &[u8],
        ) -> ConfigWriteResult {
            let result = ConfigWriteResult {
                ..Default::default()
            };
            assert!(data.len() == 1);
            self.config = data[0];
            result
        }

        fn config_register_read(&self, _reg_idx: usize) -> u32 {
            self.config as u32
        }
    }

    fn new_proxied_echo_device() -> ProxyDevice {
        let device = EchoDevice::new();
        let keep_fds: Vec<RawDescriptor> = Vec::new();
        let minijail = Minijail::new().unwrap();
        ProxyDevice::new(device, &minijail, keep_fds).unwrap()
    }

    // TODO(b/173833661): Find a way to ensure these tests are run single-threaded.
    #[test]
    #[ignore]
    fn test_debug_label() {
        let proxy_device = new_proxied_echo_device();
        assert_eq!(proxy_device.debug_label(), "EchoDevice");
    }

    #[test]
    #[ignore]
    fn test_proxied_read_write() {
        let mut proxy_device = new_proxied_echo_device();
        let address = BusAccessInfo {
            offset: 0,
            address: 0,
            id: 0,
        };
        proxy_device.write(address, &[42]);
        let mut read_buffer = [0];
        proxy_device.read(address, &mut read_buffer);
        assert_eq!(read_buffer, [42]);
    }

    #[test]
    #[ignore]
    fn test_proxied_config() {
        let mut proxy_device = new_proxied_echo_device();
        proxy_device.config_register_write(0, 0, &[42]);
        assert_eq!(proxy_device.config_register_read(0), 42);
    }
}
<|endoftext|>