/src/ipc/parent.rs

https://github.com/kpcyrd/sn0int · Rust · 144 lines · 122 code · 22 blank · 0 comment · 8 complexity · 53c9c97547cfa458505f697c686a07f0 MD5 · raw file

  1. use crate::errors::*;
  2. use crate::ipc::common::*;
  3. use chrootable_https::dns::Resolver;
  4. use crate::blobs::Blob;
  5. use crate::engine::Module;
  6. use crate::keyring::KeyRingEntry;
  7. use serde_json;
  8. use crate::worker::{Event, Event2, LogEvent, ExitEvent, EventSender, EventWithCallback};
  9. use std::collections::HashMap;
  10. use std::env;
  11. use std::ffi::OsString;
  12. use std::io::prelude::*;
  13. use std::io::{BufReader, BufRead, stdin};
  14. use std::net::SocketAddr;
  15. use std::sync::mpsc;
  16. use std::process::{Command, Child, Stdio, ChildStdin, ChildStdout};
  17. pub struct IpcParent {
  18. child: Child,
  19. stdin: ChildStdin,
  20. stdout: BufReader<ChildStdout>,
  21. }
  22. impl IpcParent {
  23. pub fn setup(module: &Module) -> Result<IpcParent> {
  24. let exe = match env::current_exe() {
  25. Ok(exe) => exe.into_os_string(),
  26. _ => OsString::from("sn0int"),
  27. };
  28. let mut child = Command::new(exe)
  29. .arg("sandbox")
  30. .arg(&module.canonical())
  31. .stdin(Stdio::piped())
  32. .stdout(Stdio::piped())
  33. .spawn()
  34. .context("Failed to spawn child process")?;
  35. let stdin = child.stdin.take().expect("Failed to take child stdin");
  36. let stdout = child.stdout.take().expect("Failed to take child stdout");
  37. let stdout = BufReader::new(stdout);
  38. Ok(IpcParent {
  39. child,
  40. stdin,
  41. stdout,
  42. })
  43. }
  44. pub fn send_start(&mut self, start: &StartCommand) -> Result<()> {
  45. let start = serde_json::to_value(&start)?;
  46. self.send(&start)?;
  47. Ok(())
  48. }
  49. pub fn send(&mut self, value: &serde_json::Value) -> Result<()> {
  50. let mut value = serde_json::to_string(value)?;
  51. value.push('\n');
  52. self.stdin.write_all(value.as_bytes())?;
  53. debug!("IpcParent sent: {:?}", value);
  54. Ok(())
  55. }
  56. pub fn send_struct<T: serde::Serialize>(&mut self, value: T, tx: &EventSender) {
  57. let value = serde_json::to_value(value).expect("Failed to serialize reply");
  58. if let Err(_) = self.send(&value) {
  59. tx.send(Event2::Log(LogEvent::Error("Failed to send to child".into())));
  60. }
  61. }
  62. pub fn recv(&mut self) -> Result<Event> {
  63. let mut line = String::new();
  64. let len = self.stdout.read_line(&mut line)?;
  65. let event = serde_json::from_str(&line[..len])?;
  66. debug!("IpcParent received: {:?}", event);
  67. Ok(event)
  68. }
  69. pub fn wait(&mut self) -> Result<()> {
  70. let exit = self.child.wait()
  71. .context("Failed to wait for child")?;
  72. if exit.success() {
  73. Ok(())
  74. } else {
  75. bail!("Child signaled error")
  76. }
  77. }
  78. pub fn send_event_callback<T: EventWithCallback>(&mut self, event: T, tx: &EventSender)
  79. where <T as EventWithCallback>::Payload: serde::Serialize
  80. {
  81. let (tx2, rx2) = mpsc::channel();
  82. tx.send(event.with_callback(tx2));
  83. let reply = rx2.recv().unwrap();
  84. self.send_struct(reply, tx);
  85. }
  86. }
  87. pub fn run(module: Module,
  88. tx: &EventSender,
  89. arg: serde_json::Value,
  90. keyring: Vec<KeyRingEntry>,
  91. verbose: u64,
  92. has_stdin: bool,
  93. proxy: Option<SocketAddr>,
  94. options: HashMap<String, String>,
  95. blobs: Vec<Blob>,
  96. ) -> Result<ExitEvent> {
  97. let dns_config = Resolver::from_system_v4()?;
  98. let mut reader = if has_stdin {
  99. Some(BufReader::new(stdin()))
  100. } else {
  101. None
  102. };
  103. let mut ipc_parent = IpcParent::setup(&module)?;
  104. ipc_parent.send_start(&StartCommand::new(verbose, keyring, dns_config, proxy, options, module, arg, blobs))?;
  105. let exit = loop {
  106. match ipc_parent.recv()? {
  107. Event::Log(event) => tx.send(Event2::Log(event)),
  108. Event::Database(object) => ipc_parent.send_event_callback(object, &tx),
  109. Event::Stdio(object) => object.apply(&mut ipc_parent, tx, &mut reader),
  110. Event::Ratelimit(req) => ipc_parent.send_event_callback(req, &tx),
  111. Event::Blob(blob) => ipc_parent.send_event_callback(blob, &tx),
  112. Event::Exit(event) => {
  113. if let ExitEvent::Err(err) = &event {
  114. tx.send(Event2::Log(LogEvent::Error(err.clone())));
  115. }
  116. break event;
  117. },
  118. }
  119. };
  120. ipc_parent.wait()?;
  121. Ok(exit)
  122. }