1use crate::{
4 errors::{APIError, CatBridgeError, FSError},
5 fsemul::{HostFilesystem, dlf::DiskLayoutFile},
6 net::{
7 DEFAULT_CAT_DEV_CHUNK_SIZE, DEFAULT_CAT_DEV_SLOWDOWN,
8 additions::{RequestIDLayer, StreamIDLayer},
9 server::{
10 Router, TCPServer,
11 requestable::{Body, State},
12 },
13 },
14};
15use bytes::{BufMut, Bytes, BytesMut};
16use local_ip_address::local_ip;
17use std::{
18 net::{IpAddr, Ipv4Addr, SocketAddrV4},
19 time::Duration,
20};
21use tokio::{
22 fs::{File, read as fs_read},
23 io::{AsyncReadExt, AsyncSeekExt, SeekFrom},
24};
25use tower::ServiceBuilder;
26use tracing::debug;
27use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value, Visit};
28
29pub const DEFAULT_ATAPI_PORT: u16 = 7974_u16;
31
32#[derive(Clone, Debug)]
38pub struct AtapiServerBuilder {
39 address: Option<Ipv4Addr>,
41 cat_dev_sleep_override: Option<Duration>,
47 chunk_override: Option<usize>,
53 fully_disable_cat_dev_sleep: bool,
55 fully_disable_chunk_override: bool,
57 host_filesystem: HostFilesystem,
59 port: Option<u16>,
61 trace_during_debug: bool,
63}
64
65impl AtapiServerBuilder {
66 #[must_use]
68 pub const fn new(host_filesystem: HostFilesystem) -> Self {
69 Self {
70 address: None,
71 cat_dev_sleep_override: None,
72 chunk_override: None,
73 fully_disable_cat_dev_sleep: false,
74 fully_disable_chunk_override: false,
75 host_filesystem,
76 port: None,
77 trace_during_debug: false,
78 }
79 }
80
81 #[must_use]
82 pub const fn address(&self) -> Option<Ipv4Addr> {
83 self.address
84 }
85 #[must_use]
86 pub const fn set_address(mut self, new_address: Option<Ipv4Addr>) -> Self {
87 self.address = new_address;
88 self
89 }
90
91 #[must_use]
92 pub const fn cat_dev_sleep_override(&self) -> Option<Duration> {
93 self.cat_dev_sleep_override
94 }
95 #[must_use]
96 pub const fn set_cat_dev_sleep_override(mut self, new_override: Option<Duration>) -> Self {
97 self.cat_dev_sleep_override = new_override;
98 self
99 }
100
101 #[must_use]
102 pub const fn chunk_override(&self) -> Option<usize> {
103 self.chunk_override
104 }
105 #[must_use]
106 pub const fn set_chunk_override(mut self, new_override: Option<usize>) -> Self {
107 self.chunk_override = new_override;
108 self
109 }
110
111 #[must_use]
112 pub const fn fully_disable_cat_dev_sleep(&self) -> bool {
113 self.fully_disable_cat_dev_sleep
114 }
115 #[must_use]
116 pub const fn set_fully_disable_cat_dev_sleep(mut self, new_value: bool) -> Self {
117 self.fully_disable_cat_dev_sleep = new_value;
118 self
119 }
120
121 #[must_use]
122 pub const fn fully_disable_chunking(&self) -> bool {
123 self.fully_disable_chunk_override
124 }
125 #[must_use]
126 pub const fn set_fully_disable_chunking(mut self, disable_chunk: bool) -> Self {
127 self.fully_disable_chunk_override = disable_chunk;
128 self
129 }
130
131 #[must_use]
132 pub const fn host_filesystem(&self) -> &HostFilesystem {
133 &self.host_filesystem
134 }
135 #[must_use]
136 pub fn set_host_filesystem(mut self, new: HostFilesystem) -> Self {
137 self.host_filesystem = new;
138 self
139 }
140
141 #[must_use]
142 pub const fn port(&self) -> Option<u16> {
143 self.port
144 }
145 #[must_use]
146 pub const fn set_port(mut self, new: Option<u16>) -> Self {
147 self.port = new;
148 self
149 }
150
151 #[must_use]
152 pub const fn trace_during_debug(&self) -> bool {
153 self.trace_during_debug
154 }
155 #[must_use]
156 pub const fn set_trace_during_debug(mut self, trace: bool) -> Self {
157 self.trace_during_debug = trace;
158 self
159 }
160
161 pub async fn build(self) -> Result<TCPServer<HostFilesystem>, CatBridgeError> {
168 let ip = self
169 .address
170 .or_else(|| {
171 local_ip().ok().map(|ip| match ip {
172 IpAddr::V4(v4) => v4,
173 IpAddr::V6(_v6) => unreachable!(),
174 })
175 })
176 .ok_or(APIError::NoHostIpFound)?;
177 let bound_address = SocketAddrV4::new(ip, self.port.unwrap_or(DEFAULT_ATAPI_PORT));
178
179 let mut router = Router::<HostFilesystem>::new();
180 router.fallback_handler(temporary_fallback_handle_all)?;
181
182 let mut server = TCPServer::new_with_state(
183 "atapi",
184 bound_address,
185 router,
186 (None, None),
187 12,
188 self.host_filesystem,
189 self.trace_during_debug,
190 )
191 .await?;
192 if self.trace_during_debug {
193 server.layer_initial_service(
194 ServiceBuilder::new()
195 .layer(RequestIDLayer::new("atapi".to_owned()))
196 .layer(StreamIDLayer),
197 );
198 } else {
199 server.layer_initial_service(
200 ServiceBuilder::new().layer(RequestIDLayer::new("atapi".to_owned())),
201 );
202 }
203 server.set_chunk_output_at_size(if self.fully_disable_chunk_override {
204 None
205 } else if let Some(over_ride) = self.chunk_override {
206 Some(over_ride)
207 } else {
208 Some(DEFAULT_CAT_DEV_CHUNK_SIZE)
209 });
210 server.set_cat_dev_slowdown(if self.fully_disable_cat_dev_sleep {
211 None
212 } else if let Some(over_ride) = self.cat_dev_sleep_override {
213 Some(over_ride)
214 } else {
215 Some(DEFAULT_CAT_DEV_SLOWDOWN)
216 });
217
218 Ok(server)
219 }
220}
221
222const ATAPI_SERVER_BUILDER_FIELDS: &[NamedField<'static>] = &[
223 NamedField::new("address"),
224 NamedField::new("cat_dev_sleep_override"),
225 NamedField::new("chunk_override"),
226 NamedField::new("fully_disable_cat_dev_sleep"),
227 NamedField::new("fully_disable_chunk_override"),
228 NamedField::new("host_filesystem"),
229 NamedField::new("port"),
230 NamedField::new("trace_during_debug"),
231];
232
233impl Structable for AtapiServerBuilder {
234 fn definition(&self) -> StructDef<'_> {
235 StructDef::new_static(
236 "AtapiServerBuilder",
237 Fields::Named(ATAPI_SERVER_BUILDER_FIELDS),
238 )
239 }
240}
241
242impl Valuable for AtapiServerBuilder {
243 fn as_value(&self) -> Value<'_> {
244 Value::Structable(self)
245 }
246
247 fn visit(&self, visitor: &mut dyn Visit) {
248 visitor.visit_named_fields(&NamedValues::new(
249 ATAPI_SERVER_BUILDER_FIELDS,
250 &[
251 Valuable::as_value(
252 &self
253 .address
254 .map_or_else(|| "<none>".to_owned(), |ip| format!("{ip}")),
255 ),
256 Valuable::as_value(
257 &self
258 .cat_dev_sleep_override
259 .map_or_else(|| "<none>".to_owned(), |dur| format!("{}s", dur.as_secs())),
260 ),
261 Valuable::as_value(&self.chunk_override),
262 Valuable::as_value(&self.fully_disable_cat_dev_sleep),
263 Valuable::as_value(&self.fully_disable_chunk_override),
264 Valuable::as_value(&self.host_filesystem),
265 Valuable::as_value(&self.port),
266 Valuable::as_value(&self.trace_during_debug),
267 ],
268 ));
269 }
270}
271
272async fn temporary_fallback_handle_all(
273 State(fs): State<HostFilesystem>,
274 Body(packet): Body<Bytes>,
275) -> Result<Option<Bytes>, CatBridgeError> {
276 match &packet[..2] {
277 [0x3, _] => {
278 debug!("Would have sent 32 bytes of various descriptions back... not sure which...");
279 }
280 [0xCF, 0x80] => {
281 debug!("ATAPI Event packet sent");
282 }
283 [0xF0, _] => {
284 return Ok(Some(Bytes::from(vec![0x0; 4])));
285 }
286 [0xF1, 0x00 | 0x02] => {
287 return Ok(Some(Bytes::from(vec![0x69; 32])));
289 }
290 [0xF1, 0x01 | 0x03] => {
291 debug!("Unknown 0xF1 packet, doesn't do anything on the network...");
292 }
293 [0xF2, _] => {
294 debug!("Got unknown 0xF2 packet: [{packet:02X?}]");
295 }
296 [0xF3, 0x00] => {
297 return handle_read_dlf(packet, &fs).await;
298 }
299 [0xF3, 0x01] => {
300 let mut data = BytesMut::with_capacity(32);
301 data.extend_from_slice(b"PC SATA EMUL");
302 data.extend_from_slice(&[0_u8; 20]);
303 return Ok(Some(data.freeze()));
304 }
305 [0xF3, 0x02 | 0x03] | [0xF5 | 0xF7, _] => {
306 debug!("Sending empty 32 bytes!");
307 return Ok(Some(Bytes::from(vec![0x0; 32])));
308 }
309 [0xF6, _] => {
310 if packet[1] & 3 != 0 {
311 debug!("F6 second byte & 3 != 0, not sending reply!");
312 } else {
313 let mut data = BytesMut::with_capacity(4);
314 data.put_u32_le(1);
315 debug!("Sent F6 reply!");
316 return Ok(Some(data.freeze()));
317 }
318 }
319 [0x12, _] => {
320 debug!("Would have sent 96 bytes of various descriptions back... not sure which...");
321 }
322 _ => {}
323 }
324
325 Ok(None)
326}
327
328async fn handle_read_dlf(
329 packet: Bytes,
330 host_filesystem: &HostFilesystem,
331) -> Result<Option<Bytes>, CatBridgeError> {
332 let read_address = u128::from(u32::from_be_bytes([
333 packet[0x4],
334 packet[0x5],
335 packet[0x6],
336 packet[0x7],
337 ])) << 11_u128;
338 let read_length = u128::from(u32::from_be_bytes([
339 packet[0x8],
340 packet[0x9],
341 packet[0xA],
342 packet[0xB],
343 ])) << 11_u128;
344 let rl_as_usize =
345 usize::try_from(read_length).map_err(|_| CatBridgeError::UnsupportedBitsPerCore)?;
346
347 debug!(
348 atapi.packet_type = "read_address",
349 atapi.read_address.address = %read_address,
350 atapi.read_address.length = %read_length,
351 "Handling atapi read request!"
352 );
353
354 let bytes_of_dlf = fs_read(host_filesystem.ppc_boot_dlf_path().await?)
355 .await
356 .map_err(FSError::from)?;
357 let dlf = DiskLayoutFile::try_from(Bytes::from(bytes_of_dlf))?;
358
359 if let Some((path, offset)) = dlf.get_path_and_offset_for_file(read_address).await {
360 let buff = {
362 let mut handle = File::open(&path).await.map_err(FSError::from)?;
363 handle
364 .seek(SeekFrom::Start(offset))
365 .await
366 .map_err(FSError::from)?;
367
368 let mut file_buff = BytesMut::zeroed(rl_as_usize);
369 let mut bytes_read = 0;
370 while bytes_read < rl_as_usize {
371 let read_this_go = handle
372 .read(&mut file_buff[bytes_read..])
373 .await
374 .map_err(FSError::IO)?;
375 if read_this_go == 0 {
377 break;
378 }
379 bytes_read += read_this_go;
380 }
381
382 file_buff
383 };
384
385 Ok(Some(buff.freeze()))
387 } else {
388 Ok(Some(BytesMut::zeroed(rl_as_usize).freeze()))
389 }
390}
391
392