tor_rpc_connect/
server.rs1use std::{io, path::PathBuf, sync::Arc};
4
5use crate::{
6 ConnectError, ResolvedConnectPoint,
7 auth::{RpcAuth, RpcCookieSource, cookie::Cookie},
8 connpt::{AddressFile, ConnectAddress},
9};
10use fs_mistrust::Mistrust;
11use tor_general_addr::general;
12use tor_rtcompat::NetStreamProvider;
13
14#[non_exhaustive]
16pub struct Listener {
17 pub listener: tor_rtcompat::general::Listener,
19 pub auth: RpcAuth,
21 pub guard: ListenerGuard,
23}
24
25pub struct ListenerGuard {
31 #[allow(unused)]
33 rm_guard: Option<UnlinkOnDrop>,
34 #[allow(unused)]
39 lock_guard: Option<fslock_guard::LockFileGuard>,
40}
41
42struct UnlinkOnDrop(PathBuf);
44impl Drop for UnlinkOnDrop {
45 fn drop(&mut self) {
46 let _ignore = std::fs::remove_file(&self.0);
47 }
48}
49
50impl ResolvedConnectPoint {
51 pub async fn bind<R>(&self, runtime: &R, mistrust: &Mistrust) -> Result<Listener, ConnectError>
53 where
54 R: NetStreamProvider<general::SocketAddr, Listener = tor_rtcompat::general::Listener>,
55 {
56 use crate::connpt::ConnectPointEnum as CptE;
57 match &self.0 {
58 CptE::Connect(connect) => connect.bind(runtime, mistrust).await,
59 CptE::Builtin(builtin) => builtin.bind(),
60 }
61 }
62}
63
64impl crate::connpt::Builtin {
65 fn bind(&self) -> Result<Listener, ConnectError> {
67 use crate::connpt::BuiltinVariant as BV;
68 match self.builtin {
69 BV::Abort => Err(ConnectError::ExplicitAbort),
70 }
71 }
72}
73
74impl crate::connpt::Connect<crate::connpt::Resolved> {
75 async fn bind<R>(&self, runtime: &R, mistrust: &Mistrust) -> Result<Listener, ConnectError>
77 where
78 R: NetStreamProvider<general::SocketAddr, Listener = tor_rtcompat::general::Listener>,
79 {
80 if let ConnectAddress::Socket(bind_to_socket) = &self.socket {
82 if let Some(sock_parent_dir) = crate::socket_parent_path(bind_to_socket.as_ref()) {
83 mistrust.make_directory(sock_parent_dir)?;
84 }
85 }
86
87 let af_unix_pathname = if let ConnectAddress::Socket(bind_to_socket) = &self.socket {
88 bind_to_socket.as_ref().as_pathname()
89 } else {
90 None
91 };
92
93 let guard = if let Some(socket_path) = af_unix_pathname {
94 let lock_path = {
106 let mut p = socket_path.to_owned();
107 p.as_mut_os_string().push(".lock");
108 p
109 };
110 let lock_guard = Some(
111 fslock_guard::LockFileGuard::try_lock(lock_path)?
112 .ok_or(ConnectError::AlreadyLocked)?,
113 );
114 match std::fs::remove_file(socket_path) {
117 Ok(()) => {}
118 Err(e) if e.kind() == io::ErrorKind::NotFound => {}
119 Err(other) => return Err(other.into()),
120 }
121
122 let rm_guard = Some(UnlinkOnDrop(socket_path.to_owned()));
123 ListenerGuard {
124 rm_guard,
125 lock_guard,
126 }
127 } else {
128 ListenerGuard {
129 rm_guard: None,
130 lock_guard: None,
131 }
132 };
133
134 let (listener, chosen_address) = self.socket.bind(runtime).await?;
135
136 if let Some(addr_file) = &self.socket_address_file {
137 let file_contents = serde_json::to_string(&AddressFile {
138 address: chosen_address.clone(),
139 })
140 .expect("Unable to serialize address!");
141
142 mistrust
143 .verifier()
144 .permit_readable()
145 .file_access()
146 .write_and_replace(addr_file, file_contents)
147 .map_err(ConnectError::SocketAddressFileAccess)?;
148 };
149
150 let auth = match &self.auth {
153 crate::connpt::Auth::None => RpcAuth::Inherent,
154 crate::connpt::Auth::Cookie { path } => RpcAuth::Cookie {
155 secret: RpcCookieSource::Loaded(Arc::new(Cookie::create(
156 path.as_path(),
157 &mut rand::rng(),
158 mistrust,
159 )?)),
160 server_address: chosen_address,
161 },
162 crate::connpt::Auth::Unrecognized(_) => return Err(ConnectError::UnsupportedAuthType),
163 };
164
165 Ok(Listener {
166 listener,
167 auth,
168 guard,
169 })
170 }
171}