1use crate::config::NodeInfo;
5use crate::pb::{hsm_server::Hsm, Empty, HsmRequest, HsmResponse, NodeConfig};
6use crate::stager;
7use anyhow::{Context, Result};
8use futures::TryFutureExt;
9use log::{debug, info, trace, warn};
10use std::path::PathBuf;
11use std::sync::Arc;
12use tonic::{Request, Response, Status};
13
14#[derive(Clone)]
18pub struct StagingHsmServer {
19 stage: Arc<stager::Stage>,
20 hsmd_sock_path: PathBuf,
21 node_info: NodeInfo,
22 node_config: NodeConfig,
23}
24
25impl StagingHsmServer {
26 pub fn new(
27 hsmd_sock_path: PathBuf,
28 stage: Arc<stager::Stage>,
29 node_info: NodeInfo,
30 node_config: NodeConfig,
31 ) -> StagingHsmServer {
32 StagingHsmServer {
33 stage,
34 hsmd_sock_path,
35 node_info,
36 node_config,
37 }
38 }
39
40 fn find_canned_response(&self, msg: &Vec<u8>) -> Option<Vec<u8>> {
42 self.node_config
43 .startupmsgs
44 .iter()
45 .find(|m| &m.request == msg)
46 .map(|m| m.response.clone())
47 }
48}
49
50#[tonic::async_trait]
51impl Hsm for StagingHsmServer {
52 async fn request(&self, request: Request<HsmRequest>) -> Result<Response<HsmResponse>, Status> {
53 let req = request.into_inner();
54 debug!("Received request from hsmproxy: {:?}", req);
55
56 if let Some(response) = self.find_canned_response(&req.raw) {
58 debug!(
59 "Returning canned response={:?} for request={:?}",
60 response, req.raw
61 );
62 return Ok(Response::new(HsmResponse {
63 request_id: req.request_id,
64 raw: response,
65 signer_state: Vec::new(),
66 }));
67 } else if req.get_type() == 11 {
68 debug!("Returning stashed init msg: {:?}", self.node_info.initmsg);
69 return Ok(Response::new(HsmResponse {
70 request_id: req.request_id,
71 raw: self.node_info.initmsg.clone(),
72 signer_state: Vec::new(), }));
74 } else if req.get_type() == 33 {
75 debug!("Returning stashed dev-memleak response");
76 return Ok(Response::new(HsmResponse {
77 request_id: req.request_id,
78 raw: vec![0, 133, 0],
79 signer_state: Vec::new(), }));
81 }
82
83 let mut chan = match self.stage.send(req).await {
84 Err(e) => {
85 return Err(Status::unknown(format!(
86 "Error while queing request from node: {:?}",
87 e
88 )))
89 }
90 Ok(c) => c,
91 };
92
93 let res = match chan.recv().await {
94 None => {
95 return Err(Status::unknown(format!(
96 "Channel closed while waiting for response",
97 )))
98 }
99 Some(r) => r,
100 };
101
102 Ok(Response::new(res))
103 }
104
105 async fn ping(&self, _request: Request<Empty>) -> Result<Response<Empty>, Status> {
106 trace!("Got a ping");
107 Ok(Response::new(Empty::default()))
108 }
109}
110
111impl StagingHsmServer {
112 pub async fn run(self) -> Result<()> {
113 let mut path = std::path::PathBuf::new();
114 path.push(std::env::current_dir().unwrap());
115 path.push(&self.hsmd_sock_path);
116 info!(
117 "Configuring hsmd interface to listen on {}",
118 path.to_str().unwrap()
119 );
120 std::fs::create_dir_all(std::path::Path::new(&path).parent().unwrap())?;
121
122 if path.exists() {
123 warn!(
124 "Socket path {} already exists, deleting",
125 path.to_string_lossy()
126 );
127 std::fs::remove_file(&path).context("removing stale hsmd socket")?;
128 }
129 let incoming = {
130 let uds = tokio::net::UnixListener::bind(path)?;
131
132 async_stream::stream! {
133 loop {
134 yield uds.accept().map_ok(|(st, _)| crate::unix::UnixStream(st)).await;
135 }
136 }
137 };
138
139 info!("HSM server interface starting.");
140 tonic::transport::Server::builder()
141 .add_service(crate::pb::hsm_server::HsmServer::new(self))
142 .serve_with_incoming(incoming)
143 .await
144 .context("serving HsmServer interface")
145 }
146}