fake_archive_accessor/fake_archive_accessor/
archivist_server.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This code is adapted and simplified from
// fuchsia-mirror/src/diagnostics/archivist/src/server.rs

use fidl::prelude::*;
use fidl_fuchsia_diagnostics::{
    BatchIteratorControlHandle, BatchIteratorRequest, BatchIteratorRequestStream, FormattedContent,
};

use futures::prelude::*;
use thiserror::Error;
use tracing::warn;
use zx_status::Status as ZxStatus;

pub struct AccessorServer {
    requests: BatchIteratorRequestStream,
}

impl AccessorServer {
    pub fn new(requests: BatchIteratorRequestStream) -> Self {
        Self { requests }
    }

    // This fails tests that try to send more data than a single VMO should hold.
    fn build_vmo(&self, data: &str) -> Result<Vec<FormattedContent>, ServerError> {
        let size = data.len() as u64;
        if size > 1024 * 1024 {
            return Err(ServerError::DataTooBig);
        }
        let vmo = zx::Vmo::create(size).map_err(ServerError::VmoCreate)?;
        vmo.write(data.as_bytes(), 0).map_err(ServerError::VmoWrite)?;
        Ok(vec![FormattedContent::Json(fidl_fuchsia_mem::Buffer { vmo, size })])
    }

    pub async fn send(mut self, data: &str) -> Result<(), ServerError> {
        if let Some(res) = self.requests.next().await {
            match res? {
                BatchIteratorRequest::GetNext { responder } => {
                    let response = self.build_vmo(data)?;
                    responder.send(Ok(response))?;
                }
                BatchIteratorRequest::WaitForReady { responder } => responder.send()?,
                BatchIteratorRequest::_UnknownMethod { .. } => {
                    unreachable!("Unexpected method call");
                }
            };
            if let Some(res) = self.requests.next().await {
                match res? {
                    BatchIteratorRequest::GetNext { responder } => responder.send(Ok(vec![]))?,
                    BatchIteratorRequest::WaitForReady { responder } => responder.send()?,
                    BatchIteratorRequest::_UnknownMethod { .. } => {
                        unreachable!("Unexpected method call");
                    }
                };
            } else {
                return Err(ServerError::TooFewBatchRequests);
            }
        } else {
            return Err(ServerError::TooFewBatchRequests);
        }
        Ok(())
    }
}

#[derive(Debug, Error)]
pub enum ServerError {
    #[error("Inspect data for test must be <1 MB")]
    DataTooBig,

    #[error("The client closed the batch connection early")]
    TooFewBatchRequests,

    #[error("data_type must be set")]
    MissingDataType,

    #[error("client_selector_configuration must be set")]
    MissingSelectors,

    #[error("no selectors were provided")]
    EmptySelectors,

    #[error("requested selectors are unsupported: {}", .0)]
    InvalidSelectors(&'static str),

    #[error("couldn't parse/validate the provided selectors")]
    ParseSelectors(#[from] selectors::Error),

    #[error("format must be set")]
    MissingFormat,

    #[error("Only Inspect supported right now")]
    UnsupportedType,

    #[error("only JSON supported right now")]
    UnsupportedFormat,

    #[error("stream_mode must be set")]
    MissingMode,

    #[error("only snapshot supported right now")]
    UnsupportedMode,

    #[error("IPC failure")]
    Ipc {
        #[from]
        source: fidl::Error,
    },

    #[error("Unable to create a VMO -- extremely unusual!")]
    VmoCreate(#[source] ZxStatus),

    #[error("Unable to write to VMO -- we may be OOMing")]
    VmoWrite(#[source] ZxStatus),
}

impl ServerError {
    pub fn close(self, control: BatchIteratorControlHandle) {
        warn!("Closing BatchIterator: {}", &self);
        let epitaph = match self {
            ServerError::MissingDataType | ServerError::DataTooBig => ZxStatus::INVALID_ARGS,
            ServerError::EmptySelectors
            | ServerError::MissingSelectors
            | ServerError::InvalidSelectors(_)
            | ServerError::ParseSelectors(_) => ZxStatus::INVALID_ARGS,
            ServerError::VmoCreate(status) | ServerError::VmoWrite(status) => status,
            ServerError::MissingFormat | ServerError::MissingMode => ZxStatus::INVALID_ARGS,
            ServerError::UnsupportedFormat
            | ServerError::UnsupportedMode
            | ServerError::UnsupportedType => ZxStatus::WRONG_TYPE,
            ServerError::Ipc { .. } | ServerError::TooFewBatchRequests => ZxStatus::IO,
        };
        control.shutdown_with_epitaph(epitaph);
    }
}