server.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::{collections::HashSet, io::ErrorKind, sync::Arc};
  19. use async_trait::async_trait;
  20. use log::{debug, error, info};
  21. use smol::lock::MutexGuard;
  22. use tinyjson::JsonValue;
  23. use url::Url;
  24. use super::{
  25. common::{read_from_stream, write_to_stream, INIT_BUF_SIZE},
  26. jsonrpc::*,
  27. };
  28. use crate::{
  29. net::transport::{Listener, PtListener, PtStream},
  30. system::{StoppableTask, StoppableTaskPtr},
  31. Error, Result,
  32. };
  33. /// Asynchronous trait implementing a handler for incoming JSON-RPC requests.
  34. #[async_trait]
  35. pub trait RequestHandler: Sync + Send {
  36. async fn handle_request(&self, req: JsonRequest) -> JsonResult;
  37. async fn pong(&self, id: u16, _params: JsonValue) -> JsonResult {
  38. JsonResponse::new(JsonValue::String("pong".to_string()), id).into()
  39. }
  40. async fn connections_mut(&self) -> MutexGuard<'_, HashSet<StoppableTaskPtr>>;
  41. async fn connections(&self) -> Vec<StoppableTaskPtr> {
  42. self.connections_mut().await.iter().cloned().collect()
  43. }
  44. async fn mark_connection(&self, task: StoppableTaskPtr) {
  45. self.connections_mut().await.insert(task);
  46. }
  47. async fn unmark_connection(&self, task: StoppableTaskPtr) {
  48. self.connections_mut().await.remove(&task);
  49. }
  50. async fn active_connections(&self) -> usize {
  51. self.connections_mut().await.len()
  52. }
  53. async fn stop_connections(&self) {
  54. info!(target: "rpc::server", "[RPC] Server stopped, closing connections");
  55. for (i, task) in self.connections().await.iter().enumerate() {
  56. debug!(target: "rpc::server", "Stopping connection #{}", i);
  57. task.stop().await;
  58. }
  59. }
  60. }
  61. /// Accept function that should run inside a loop for accepting incoming
  62. /// JSON-RPC requests and passing them to the [`RequestHandler`].
  63. pub async fn accept(
  64. mut stream: Box<dyn PtStream>,
  65. addr: Url,
  66. rh: Arc<impl RequestHandler + 'static>,
  67. conn_limit: Option<usize>,
  68. ) -> Result<()> {
  69. // If there's a connection limit set, we will refuse connections
  70. // after this point.
  71. if let Some(conn_limit) = conn_limit {
  72. if rh.clone().active_connections().await >= conn_limit {
  73. debug!(
  74. target: "rpc::server::accept()",
  75. "Connection limit reached, refusing new conn"
  76. );
  77. return Err(Error::RpcConnectionsExhausted)
  78. }
  79. }
  80. loop {
  81. let mut buf = Vec::with_capacity(INIT_BUF_SIZE);
  82. let _ = read_from_stream(&mut stream, &mut buf, false).await?;
  83. let val: JsonValue = String::from_utf8(buf)?.parse()?;
  84. let req = JsonRequest::try_from(&val)?;
  85. debug!(target: "rpc::server", "{} --> {}", addr, val.stringify()?);
  86. let rep = rh.handle_request(req).await;
  87. match rep {
  88. JsonResult::Subscriber(subscriber) => {
  89. // Subscribe to the inner method subscriber
  90. let subscription = subscriber.sub.subscribe().await;
  91. loop {
  92. // Listen for notifications
  93. let notification = subscription.receive().await;
  94. // Push notification
  95. debug!(target: "rpc::server", "{} <-- {}", addr, notification.stringify()?);
  96. let notification = JsonResult::Notification(notification);
  97. if let Err(e) = write_to_stream(&mut stream, &notification).await {
  98. subscription.unsubscribe().await;
  99. return Err(e)
  100. }
  101. }
  102. }
  103. JsonResult::Request(_) | JsonResult::Notification(_) => {
  104. unreachable!("Should never happen")
  105. }
  106. JsonResult::Response(ref v) => {
  107. debug!(target: "rpc::server", "{} <-- {}", addr, v.stringify()?);
  108. write_to_stream(&mut stream, &rep).await?;
  109. }
  110. JsonResult::Error(ref v) => {
  111. debug!(target: "rpc::server", "{} <-- {}", addr, v.stringify()?);
  112. write_to_stream(&mut stream, &rep).await?;
  113. }
  114. }
  115. }
  116. }
  117. /// Wrapper function around [`accept()`] to take the incoming connection and
  118. /// pass it forward.
  119. async fn run_accept_loop(
  120. listener: Box<dyn PtListener>,
  121. rh: Arc<impl RequestHandler + 'static>,
  122. conn_limit: Option<usize>,
  123. ex: Arc<smol::Executor<'_>>,
  124. ) -> Result<()> {
  125. loop {
  126. match listener.next().await {
  127. Ok((stream, url)) => {
  128. let rh_ = rh.clone();
  129. info!(target: "rpc::server", "[RPC] Server accepted conn from {}", url);
  130. let task = StoppableTask::new();
  131. let task_ = task.clone();
  132. task.clone().start(
  133. accept(stream, url.clone(), rh.clone(), conn_limit),
  134. |_| async move {
  135. rh_.clone().unmark_connection(task_.clone()).await;
  136. },
  137. Error::ChannelStopped,
  138. ex.clone(),
  139. );
  140. rh.clone().mark_connection(task.clone()).await;
  141. }
  142. // As per accept(2) recommendation:
  143. Err(e) if e.raw_os_error().is_some() => match e.raw_os_error().unwrap() {
  144. libc::EAGAIN | libc::ECONNABORTED | libc::EPROTO | libc::EINTR => continue,
  145. _ => {
  146. error!(
  147. target: "rpc::server::run_accept_loop()",
  148. "[RPC] Server failed listening: {}", e,
  149. );
  150. error!(
  151. target: "rpc::server::run_accept_loop()",
  152. "[RPC] Closing accept loop"
  153. );
  154. return Err(e.into())
  155. }
  156. },
  157. // In case a TLS handshake fails, we'll get this:
  158. Err(e) if e.kind() == ErrorKind::UnexpectedEof => continue,
  159. // Errors we didn't handle above:
  160. Err(e) => {
  161. error!(
  162. target: "rpc::server::run_accept_loop()",
  163. "[RPC] Unhandled listener.next() error: {}", e,
  164. );
  165. error!(
  166. target: "rpc::server::run_accept_loop()",
  167. "[RPC] Closing acceptloop"
  168. );
  169. return Err(e.into())
  170. }
  171. }
  172. }
  173. }
  174. /// Start a JSON-RPC server bound to the given accept URL and use the
  175. /// given [`RequestHandler`] to handle incoming requests.
  176. pub async fn listen_and_serve(
  177. accept_url: Url,
  178. rh: Arc<impl RequestHandler + 'static>,
  179. conn_limit: Option<usize>,
  180. ex: Arc<smol::Executor<'_>>,
  181. ) -> Result<()> {
  182. let listener = Listener::new(accept_url).await?.listen().await?;
  183. run_accept_loop(listener, rh, conn_limit, ex.clone()).await
  184. }
  185. #[cfg(test)]
  186. mod tests {
  187. use super::*;
  188. use crate::{rpc::client::RpcClient, system::msleep};
  189. use smol::{lock::Mutex, net::TcpListener, Executor};
  190. struct RpcServer {
  191. rpc_connections: Mutex<HashSet<StoppableTaskPtr>>,
  192. }
  193. #[async_trait]
  194. impl RequestHandler for RpcServer {
  195. async fn handle_request(&self, req: JsonRequest) -> JsonResult {
  196. match req.method.as_str() {
  197. "ping" => return self.pong(req.id, req.params).await,
  198. _ => panic!(),
  199. }
  200. }
  201. async fn connections_mut(&self) -> MutexGuard<'_, HashSet<StoppableTaskPtr>> {
  202. self.rpc_connections.lock().await
  203. }
  204. }
  205. #[test]
  206. fn conn_manager() -> Result<()> {
  207. let executor = Arc::new(Executor::new());
  208. // This simulates a server and a client. Through the function, there
  209. // are some calls to sleep(), which are used for the tests, because
  210. // otherwise they execute too fast. In practice, The RPC server is
  211. // a long-running task so when polled, it should handle things in a
  212. // correct manner.
  213. smol::block_on(executor.run(async {
  214. // Find an available port
  215. let listener = TcpListener::bind("127.0.0.1:0").await?;
  216. let sockaddr = listener.local_addr()?;
  217. let endpoint = Url::parse(&format!("tcp://127.0.0.1:{}", sockaddr.port()))?;
  218. drop(listener);
  219. let rpc_server = Arc::new(RpcServer { rpc_connections: Mutex::new(HashSet::new()) });
  220. let rpc_server_ = rpc_server.clone();
  221. let server_task = StoppableTask::new();
  222. server_task.clone().start(
  223. listen_and_serve(endpoint.clone(), rpc_server.clone(), None, executor.clone()),
  224. |res| async move {
  225. match res {
  226. Ok(()) | Err(Error::RpcServerStopped) => {
  227. rpc_server_.stop_connections().await
  228. }
  229. Err(e) => panic!("{}", e),
  230. }
  231. },
  232. Error::RpcServerStopped,
  233. executor.clone(),
  234. );
  235. // Let the server spawn
  236. msleep(500).await;
  237. // Connect a client
  238. let rpc_client0 = RpcClient::new(endpoint.clone(), executor.clone()).await?;
  239. msleep(500).await;
  240. assert!(rpc_server.active_connections().await == 1);
  241. // Connect another client
  242. let rpc_client1 = RpcClient::new(endpoint.clone(), executor.clone()).await?;
  243. msleep(500).await;
  244. assert!(rpc_server.active_connections().await == 2);
  245. // And another one
  246. let _rpc_client2 = RpcClient::new(endpoint.clone(), executor.clone()).await?;
  247. msleep(500).await;
  248. assert!(rpc_server.active_connections().await == 3);
  249. // Close the first client
  250. rpc_client0.close().await?;
  251. msleep(500).await;
  252. assert!(rpc_server.active_connections().await == 2);
  253. // Close the second client
  254. rpc_client1.close().await?;
  255. msleep(500).await;
  256. assert!(rpc_server.active_connections().await == 1);
  257. // The Listener should be stopped when we stop the server task.
  258. server_task.stop().await;
  259. assert!(RpcClient::new(endpoint, executor.clone()).await.is_err());
  260. // After the server is stopped, the connections tasks should also be stopped
  261. assert!(rpc_server.active_connections().await == 0);
  262. Ok(())
  263. }))
  264. }
  265. }