|
@@ -1,77 +1,70 @@
|
|
|
-use async_std::{
|
|
|
|
|
- io::{ReadExt, WriteExt},
|
|
|
|
|
- sync::Arc,
|
|
|
|
|
-};
|
|
|
|
|
-use std::{env, fs};
|
|
|
|
|
-
|
|
|
|
|
|
|
+//! JSON-RPC server-side implementation.
|
|
|
|
|
+use async_std::sync::Arc;
|
|
|
use async_trait::async_trait;
|
|
use async_trait::async_trait;
|
|
|
-use log::{debug, error, info};
|
|
|
|
|
|
|
+use futures::{AsyncReadExt, AsyncWriteExt};
|
|
|
|
|
+use log::{debug, error, info, warn};
|
|
|
use url::Url;
|
|
use url::Url;
|
|
|
|
|
|
|
|
use super::jsonrpc::{JsonRequest, JsonResult};
|
|
use super::jsonrpc::{JsonRequest, JsonResult};
|
|
|
use crate::{
|
|
use crate::{
|
|
|
- net::transport::{
|
|
|
|
|
- TcpTransport, TorTransport, Transport, TransportListener, TransportName, TransportStream,
|
|
|
|
|
- UnixTransport,
|
|
|
|
|
|
|
+ net::{
|
|
|
|
|
+ transport::Transport, TcpTransport, TorTransport, TransportListener, TransportName,
|
|
|
|
|
+ TransportStream, UnixTransport,
|
|
|
},
|
|
},
|
|
|
Error, Result,
|
|
Error, Result,
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+/// Asynchronous trait implementing a handler for incoming JSON-RPC requests.
|
|
|
|
|
+/// Can be used by matching on methods and branching out to functions that
|
|
|
|
|
+/// handle respective methods.
|
|
|
#[async_trait]
|
|
#[async_trait]
|
|
|
pub trait RequestHandler: Sync + Send {
|
|
pub trait RequestHandler: Sync + Send {
|
|
|
async fn handle_request(&self, req: JsonRequest) -> JsonResult;
|
|
async fn handle_request(&self, req: JsonRequest) -> JsonResult;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-async fn run_accept_loop(
|
|
|
|
|
- listener: Box<dyn TransportListener>,
|
|
|
|
|
- rh: Arc<impl RequestHandler + 'static>,
|
|
|
|
|
-) -> Result<()> {
|
|
|
|
|
- while let Ok((stream, peer_addr)) = listener.next().await {
|
|
|
|
|
- info!(target: "JSON-RPC SERVER", "RPC Accepted connection {}", peer_addr);
|
|
|
|
|
- accept(stream, rh.clone()).await?;
|
|
|
|
|
- }
|
|
|
|
|
- Ok(())
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
|
|
+/// Internal accept function that runs inside a loop for accepting incoming
|
|
|
|
|
+/// JSON-RPC requests and passing them to the [`RequestHandler`].
|
|
|
async fn accept(
|
|
async fn accept(
|
|
|
mut stream: Box<dyn TransportStream>,
|
|
mut stream: Box<dyn TransportStream>,
|
|
|
|
|
+ peer_addr: Url,
|
|
|
rh: Arc<impl RequestHandler + 'static>,
|
|
rh: Arc<impl RequestHandler + 'static>,
|
|
|
) -> Result<()> {
|
|
) -> Result<()> {
|
|
|
- let mut buf = vec![0; 8192];
|
|
|
|
|
-
|
|
|
|
|
loop {
|
|
loop {
|
|
|
|
|
+ // Nasty size
|
|
|
|
|
+ let mut buf = vec![0; 2048 * 10];
|
|
|
|
|
+
|
|
|
let n = match stream.read(&mut buf).await {
|
|
let n = match stream.read(&mut buf).await {
|
|
|
Ok(n) if n == 0 => {
|
|
Ok(n) if n == 0 => {
|
|
|
- info!(target: "JSON-RPC SERVER", "Closed connection");
|
|
|
|
|
|
|
+ debug!(target: "jsonrpc-server", "Closed connection for {}", peer_addr);
|
|
|
break
|
|
break
|
|
|
}
|
|
}
|
|
|
Ok(n) => n,
|
|
Ok(n) => n,
|
|
|
Err(e) => {
|
|
Err(e) => {
|
|
|
- error!(target: "JSON-RPC SERVER", "Failed reading from socket: {}", e);
|
|
|
|
|
- info!(target: "JSON-RPC SERVER", "Closed connection");
|
|
|
|
|
|
|
+ error!("JSON-RPC server failed reading from {} socket: {}", peer_addr, e);
|
|
|
|
|
+ debug!(target: "jsonrpc-server", "Closed connection for {}", peer_addr);
|
|
|
break
|
|
break
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
let r: JsonRequest = match serde_json::from_slice(&buf[0..n]) {
|
|
let r: JsonRequest = match serde_json::from_slice(&buf[0..n]) {
|
|
|
Ok(r) => {
|
|
Ok(r) => {
|
|
|
- debug!(target: "JSON-RPC SERVER", "--> {}", String::from_utf8_lossy(&buf));
|
|
|
|
|
|
|
+ debug!(target: "jsonrpc-server", "{} --> {}", peer_addr, String::from_utf8_lossy(&buf));
|
|
|
r
|
|
r
|
|
|
}
|
|
}
|
|
|
Err(e) => {
|
|
Err(e) => {
|
|
|
- error!(target: "JSON-RPC SERVER", "Received invalid JSON: {:?}", e);
|
|
|
|
|
- info!(target: "JSON-RPC SERVER", "Closed connection");
|
|
|
|
|
|
|
+ warn!("JSON-RPC server received invalid JSON from {}: {}", peer_addr, e);
|
|
|
|
|
+ debug!(target: "jsonrpc-server", "Closed connection for {}", peer_addr);
|
|
|
break
|
|
break
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
let reply = rh.handle_request(r).await;
|
|
let reply = rh.handle_request(r).await;
|
|
|
- let j = serde_json::to_string(&reply)?;
|
|
|
|
|
- debug!(target: "JSON-RPC SERVER", "<-- {}", j);
|
|
|
|
|
|
|
+ let j = serde_json::to_string(&reply).unwrap();
|
|
|
|
|
+ debug!(target: "jsonrpc-server", "{} <-- {}", peer_addr, j);
|
|
|
|
|
|
|
|
if let Err(e) = stream.write_all(j.as_bytes()).await {
|
|
if let Err(e) = stream.write_all(j.as_bytes()).await {
|
|
|
- error!(target: "JSON-RPC SERVER", "Failed writing to socket: {}", e);
|
|
|
|
|
- info!(target: "JSON-RPC SERVER", "Closed connection");
|
|
|
|
|
|
|
+ error!("JSON-RPC server failed writing to {} socket: {}", peer_addr, e);
|
|
|
|
|
+ debug!(target: "jsonrpc-server", "Closed connection for {}", peer_addr);
|
|
|
break
|
|
break
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -79,36 +72,50 @@ async fn accept(
|
|
|
Ok(())
|
|
Ok(())
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/// Wrapper function around [`accept`] to take the incoming connection and
|
|
|
|
|
+/// pass it forward.
|
|
|
|
|
+async fn run_accept_loop(
|
|
|
|
|
+ listener: Box<dyn TransportListener>,
|
|
|
|
|
+ rh: Arc<impl RequestHandler + 'static>,
|
|
|
|
|
+) -> Result<()> {
|
|
|
|
|
+ while let Ok((stream, peer_addr)) = listener.next().await {
|
|
|
|
|
+ info!("JSON-RPC server accepted connection from {}", peer_addr);
|
|
|
|
|
+ accept(stream, peer_addr, rh.clone()).await?;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Ok(())
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/// Start a JSON-RPC server bound to the given accept URL and use the given
|
|
|
|
|
+/// [`RequestHandler`] to handle incoming requests.
|
|
|
pub async fn listen_and_serve(
|
|
pub async fn listen_and_serve(
|
|
|
accept_url: Url,
|
|
accept_url: Url,
|
|
|
rh: Arc<impl RequestHandler + 'static>,
|
|
rh: Arc<impl RequestHandler + 'static>,
|
|
|
) -> Result<()> {
|
|
) -> Result<()> {
|
|
|
- debug!(target: "JSON-RPC SERVER", "Trying to start listener on {}", accept_url);
|
|
|
|
|
|
|
+ debug!(target: "jsonrpc-server", "Trying to bind listener on {}", accept_url);
|
|
|
|
|
|
|
|
macro_rules! accept {
|
|
macro_rules! accept {
|
|
|
($listener:expr, $transport:expr, $upgrade:expr) => {{
|
|
($listener:expr, $transport:expr, $upgrade:expr) => {{
|
|
|
if let Err(err) = $listener {
|
|
if let Err(err) = $listener {
|
|
|
- error!("Setup for {} failed: {}", accept_url, err);
|
|
|
|
|
|
|
+ error!("JSON-RPC server setup for {} failed: {}", accept_url, err);
|
|
|
return Err(Error::BindFailed(accept_url.as_str().into()))
|
|
return Err(Error::BindFailed(accept_url.as_str().into()))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
let listener = $listener?.await;
|
|
let listener = $listener?.await;
|
|
|
-
|
|
|
|
|
if let Err(err) = listener {
|
|
if let Err(err) = listener {
|
|
|
- error!("Bind listener to {} failed: {}", accept_url, err);
|
|
|
|
|
|
|
+ error!("JSON-RPC listener bind to {} failed: {}", accept_url, err);
|
|
|
return Err(Error::BindFailed(accept_url.as_str().into()))
|
|
return Err(Error::BindFailed(accept_url.as_str().into()))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
let listener = listener?;
|
|
let listener = listener?;
|
|
|
-
|
|
|
|
|
match $upgrade {
|
|
match $upgrade {
|
|
|
None => {
|
|
None => {
|
|
|
- info!("RPC listening to: {}", accept_url);
|
|
|
|
|
|
|
+ info!("JSON-RPC listener bound to {}", accept_url);
|
|
|
run_accept_loop(Box::new(listener), rh).await?;
|
|
run_accept_loop(Box::new(listener), rh).await?;
|
|
|
}
|
|
}
|
|
|
Some(u) if u == "tls" => {
|
|
Some(u) if u == "tls" => {
|
|
|
- info!("RPC listening to: {}", accept_url);
|
|
|
|
|
let tls_listener = $transport.upgrade_listener(listener)?.await?;
|
|
let tls_listener = $transport.upgrade_listener(listener)?.await?;
|
|
|
|
|
+ info!("JSON-RPC listener bound to {}", accept_url);
|
|
|
run_accept_loop(Box::new(tls_listener), rh).await?;
|
|
run_accept_loop(Box::new(tls_listener), rh).await?;
|
|
|
}
|
|
}
|
|
|
Some(u) => return Err(Error::UnsupportedTransportUpgrade(u)),
|
|
Some(u) => return Err(Error::UnsupportedTransportUpgrade(u)),
|
|
@@ -124,53 +131,24 @@ pub async fn listen_and_serve(
|
|
|
accept!(listener, transport, upgrade);
|
|
accept!(listener, transport, upgrade);
|
|
|
}
|
|
}
|
|
|
TransportName::Tor(upgrade) => {
|
|
TransportName::Tor(upgrade) => {
|
|
|
- let socks5_url = Url::parse(
|
|
|
|
|
- &env::var("DARKFI_TOR_SOCKS5_URL")
|
|
|
|
|
- .unwrap_or_else(|_| "socks5://127.0.0.1:9050".to_string()),
|
|
|
|
|
- )?;
|
|
|
|
|
-
|
|
|
|
|
- let torc_url = Url::parse(
|
|
|
|
|
- &env::var("DARKFI_TOR_CONTROL_URL")
|
|
|
|
|
- .unwrap_or_else(|_| "tcp://127.0.0.1:9051".to_string()),
|
|
|
|
|
- )?;
|
|
|
|
|
-
|
|
|
|
|
- let auth_cookie = env::var("DARKFI_TOR_COOKIE");
|
|
|
|
|
-
|
|
|
|
|
- if auth_cookie.is_err() {
|
|
|
|
|
- return Err(Error::TorError(
|
|
|
|
|
- "Please set the env var DARKFI_TOR_COOKIE to the configured tor cookie file. \
|
|
|
|
|
- For example: \
|
|
|
|
|
- \'export DARKFI_TOR_COOKIE=\"/var/lib/tor/control_auth_cookie\"\'"
|
|
|
|
|
- .to_string(),
|
|
|
|
|
- ))
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- let auth_cookie = auth_cookie.unwrap();
|
|
|
|
|
-
|
|
|
|
|
- let auth_cookie = hex::encode(&fs::read(auth_cookie).unwrap());
|
|
|
|
|
-
|
|
|
|
|
|
|
+ let (socks5_url, torc_url, auth_cookie) = TorTransport::get_env()?;
|
|
|
|
|
+ let auth_cookie = hex::encode(&std::fs::read(auth_cookie).unwrap());
|
|
|
let transport = TorTransport::new(socks5_url, Some((torc_url, auth_cookie)))?;
|
|
let transport = TorTransport::new(socks5_url, Some((torc_url, auth_cookie)))?;
|
|
|
|
|
|
|
|
- // generate EHS pointing to local address
|
|
|
|
|
|
|
+ // Generate EHS pointing to local address
|
|
|
let hurl = transport.create_ehs(accept_url.clone())?;
|
|
let hurl = transport.create_ehs(accept_url.clone())?;
|
|
|
-
|
|
|
|
|
- info!("EHS TOR: {}", hurl.to_string());
|
|
|
|
|
|
|
+ info!("Created ephemeral hidden service: {}", hurl.to_string());
|
|
|
|
|
|
|
|
let listener = transport.clone().listen_on(accept_url.clone());
|
|
let listener = transport.clone().listen_on(accept_url.clone());
|
|
|
-
|
|
|
|
|
accept!(listener, transport, upgrade);
|
|
accept!(listener, transport, upgrade);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
TransportName::Unix => {
|
|
TransportName::Unix => {
|
|
|
let transport = UnixTransport::new();
|
|
let transport = UnixTransport::new();
|
|
|
-
|
|
|
|
|
let listener = transport.listen(accept_url.clone()).await;
|
|
let listener = transport.listen(accept_url.clone()).await;
|
|
|
-
|
|
|
|
|
if let Err(err) = listener {
|
|
if let Err(err) = listener {
|
|
|
- error!("RPC Bind listener to {} failed: {}", accept_url, err);
|
|
|
|
|
|
|
+ error!("JSON-RPC Unix socket bind to {} failed: {}", accept_url, err);
|
|
|
return Err(Error::BindFailed(accept_url.as_str().into()))
|
|
return Err(Error::BindFailed(accept_url.as_str().into()))
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
run_accept_loop(Box::new(listener?), rh).await?;
|
|
run_accept_loop(Box::new(listener?), rh).await?;
|
|
|
}
|
|
}
|
|
|
_ => unimplemented!(),
|
|
_ => unimplemented!(),
|