1pub mod client;
20pub mod server;
21#[cfg(test)]
22mod tests;
23
24mod uid;
25
26pub(crate) mod pdata;
27
28use std::{
29 backtrace::Backtrace,
30 io::{BufRead, BufReader, Cursor, Read},
31 time::Duration,
32};
33
34use bytes::{Buf, BytesMut};
35#[cfg(feature = "async")]
36pub use client::AsyncClientAssociation;
37pub use client::{ClientAssociation, ClientAssociationOptions};
38#[cfg(feature = "async")]
39pub use pdata::non_blocking::AsyncPDataWriter;
40pub use pdata::{PDataReader, PDataWriter};
41#[cfg(feature = "async")]
42pub use server::AsyncServerAssociation;
43pub use server::{ServerAssociation, ServerAssociationOptions};
44use snafu::{ensure, ResultExt, Snafu};
45
46use crate::{
47 pdu::{self, AssociationRJ, PresentationContextNegotiated, ReadPduSnafu, UserVariableItem},
48 write_pdu, Pdu,
49};
50
51type Result<T, E = Error> = std::result::Result<T, E>;
52
53#[derive(Debug, Snafu)]
54#[non_exhaustive]
55pub enum Error {
56 MissingAbstractSyntax { backtrace: Backtrace },
58
59 ToAddress {
61 source: std::io::Error,
62 backtrace: Backtrace,
63 },
64
65 Connect {
67 source: std::io::Error,
68 backtrace: Backtrace,
69 },
70
71 SetReadTimeout {
73 source: std::io::Error,
74 backtrace: Backtrace,
75 },
76
77 SetWriteTimeout {
79 source: std::io::Error,
80 backtrace: Backtrace,
81 },
82
83 #[snafu(display("failed to send pdu: {}", source))]
85 SendPdu {
86 #[snafu(backtrace)]
87 source: crate::pdu::WriteError,
88 },
89
90 #[snafu(display("failed to receive pdu: {}", source))]
92 ReceivePdu {
93 #[snafu(backtrace)]
94 source: crate::pdu::ReadError,
95 },
96
97 #[snafu(display("unexpected response from peer `{:?}`", pdu))]
98 #[non_exhaustive]
99 UnexpectedPdu {
100 pdu: Box<Pdu>,
102 },
103
104 #[snafu(display("unknown response from peer `{:?}`", pdu))]
105 #[non_exhaustive]
106 UnknownPdu {
107 pdu: Box<Pdu>,
109 },
110
111 #[snafu(display("protocol version mismatch: expected {}, got {}", expected, got))]
112 ProtocolVersionMismatch {
113 expected: u16,
114 got: u16,
115 backtrace: Backtrace,
116 },
117
118 #[snafu(display("association rejected {}", association_rj.source))]
120 Rejected {
121 association_rj: AssociationRJ,
122 backtrace: Backtrace,
123 },
124
125 Aborted { backtrace: Backtrace },
127
128 NoAcceptedPresentationContexts { backtrace: Backtrace },
130
131 #[non_exhaustive]
133 WireSend {
134 source: std::io::Error,
135 backtrace: Backtrace,
136 },
137
138 #[non_exhaustive]
140 WireRead {
141 source: std::io::Error,
142 backtrace: Backtrace,
143 },
144
145 #[non_exhaustive]
147 Timeout {
148 source: std::io::Error,
149 backtrace: Backtrace,
150 },
151
152 #[snafu(display("failed close connection: {}", source))]
153 Close {
154 source: std::io::Error,
155 backtrace: Backtrace,
156 },
157
158 #[snafu(display(
159 "PDU is too large ({} bytes) to be sent to the remote application entity",
160 length
161 ))]
162 #[non_exhaustive]
163 SendTooLongPdu { length: usize, backtrace: Backtrace },
164
165 #[snafu(display("Connection closed by peer"))]
166 ConnectionClosed,
167
168 #[cfg(feature = "sync-tls")]
170 #[snafu(display("TLS configuration is required but not provided"))]
171 TlsConfigMissing { backtrace: Backtrace },
172
173 #[cfg(feature = "sync-tls")]
175 #[snafu(display("Invalid server name for TLS connection"))]
176 InvalidServerName {
177 source: rustls::pki_types::InvalidDnsNameError,
178 backtrace: Backtrace,
179 },
180
181 #[cfg(feature = "sync-tls")]
183 #[snafu(display("Failed to establish TLS connection: {:?}", source))]
184 TlsConnection {
185 source: rustls::Error,
186 backtrace: Backtrace,
187 },
188}
189pub(crate) struct NegotiatedOptions {
191 peer_max_pdu_length: u32,
193 user_variables: Vec<UserVariableItem>,
195 presentation_contexts: Vec<PresentationContextNegotiated>,
197 peer_ae_title: String,
199}
200
201#[derive(Debug, Clone, Copy, Default)]
203pub(crate) struct SocketOptions {
204 read_timeout: Option<Duration>,
206 write_timeout: Option<Duration>,
208 connection_timeout: Option<Duration>,
210}
211
212pub trait CloseSocket {
214 fn close(&mut self) -> std::io::Result<()>;
215}
216
217impl CloseSocket for std::net::TcpStream {
218 fn close(&mut self) -> std::io::Result<()> {
219 self.shutdown(std::net::Shutdown::Both)
220 }
221}
222
223#[cfg(feature = "sync-tls")]
224impl CloseSocket for rustls::StreamOwned<rustls::ClientConnection, std::net::TcpStream> {
225 fn close(&mut self) -> std::io::Result<()> {
226 self.get_mut().shutdown(std::net::Shutdown::Both)
227 }
228}
229
230#[cfg(feature = "sync-tls")]
231impl CloseSocket for rustls::StreamOwned<rustls::ServerConnection, std::net::TcpStream> {
232 fn close(&mut self) -> std::io::Result<()> {
233 self.get_mut().shutdown(std::net::Shutdown::Both)
234 }
235}
236
237pub trait Association {
239 fn peer_ae_title(&self) -> &str;
241
242 fn acceptor_max_pdu_length(&self) -> u32;
245
246 fn requestor_max_pdu_length(&self) -> u32;
249
250 fn local_max_pdu_length(&self) -> u32;
260
261 fn peer_max_pdu_length(&self) -> u32;
267
268 fn presentation_contexts(&self) -> &[PresentationContextNegotiated];
270
271 fn user_variables(&self) -> &[UserVariableItem];
276}
277
278mod private {
279 use crate::{
280 pdu::{AbortRQServiceProviderReason, AbortRQSource},
281 Pdu,
282 };
283 use snafu::ResultExt;
284
285 pub trait SyncAssociationSealed<S: std::io::Read + std::io::Write + super::CloseSocket> {
294 fn close(&mut self) -> std::io::Result<()>;
295 fn send(&mut self, pdu: &Pdu) -> super::Result<()>;
296 fn receive(&mut self) -> super::Result<Pdu>;
297 fn release(&mut self) -> super::Result<()> {
298 let pdu = Pdu::ReleaseRQ;
299 self.send(&pdu)?;
300 let pdu = self.receive()?;
301
302 match pdu {
303 Pdu::ReleaseRP => {}
304 pdu @ Pdu::AbortRQ { .. }
305 | pdu @ Pdu::AssociationAC { .. }
306 | pdu @ Pdu::AssociationRJ { .. }
307 | pdu @ Pdu::AssociationRQ { .. }
308 | pdu @ Pdu::PData { .. }
309 | pdu @ Pdu::ReleaseRQ => return super::UnexpectedPduSnafu { pdu }.fail(),
310 pdu @ Pdu::Unknown { .. } => return super::UnknownPduSnafu { pdu }.fail(),
311 }
312 self.close().context(super::CloseSnafu)?;
313 Ok(())
314 }
315
316 fn abort(&mut self) -> super::Result<()>
317 where
318 Self: Sized,
319 {
320 let pdu = Pdu::AbortRQ {
321 source: AbortRQSource::ServiceProvider(
322 AbortRQServiceProviderReason::ReasonNotSpecified,
323 ),
324 };
325 let out = self.send(&pdu);
326 let _ = self.close();
327 out
328 }
329 }
330
331 #[cfg(feature = "async")]
340 pub trait AsyncAssociationSealed<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin> {
341 fn close(&mut self) -> impl std::future::Future<Output = std::io::Result<()>> + Send
342 where
343 Self: Send;
344 fn send(
345 &mut self,
346 pdu: &Pdu,
347 ) -> impl std::future::Future<Output = super::Result<()>> + Send
348 where
349 Self: Send;
350 fn receive(&mut self) -> impl std::future::Future<Output = super::Result<Pdu>> + Send
351 where
352 Self: Send;
353 fn release(&mut self) -> impl std::future::Future<Output = super::Result<()>> + Send
354 where
355 Self: Send,
356 {
357 async move {
358 let pdu = Pdu::ReleaseRQ;
359 self.send(&pdu).await?;
360 let pdu = self.receive().await?;
361
362 match pdu {
363 Pdu::ReleaseRP => {}
364 pdu @ Pdu::AbortRQ { .. }
365 | pdu @ Pdu::AssociationAC { .. }
366 | pdu @ Pdu::AssociationRJ { .. }
367 | pdu @ Pdu::AssociationRQ { .. }
368 | pdu @ Pdu::PData { .. }
369 | pdu @ Pdu::ReleaseRQ => return super::UnexpectedPduSnafu { pdu }.fail(),
370 pdu @ Pdu::Unknown { .. } => return super::UnknownPduSnafu { pdu }.fail(),
371 }
372 self.close().await.context(super::CloseSnafu)?;
373 Ok(())
374 }
375 }
376
377 fn abort(&mut self) -> impl std::future::Future<Output = super::Result<()>> + Send
378 where
379 Self: Sized + Send,
380 {
381 let pdu = Pdu::AbortRQ {
382 source: AbortRQSource::ServiceProvider(
383 AbortRQServiceProviderReason::ReasonNotSpecified,
384 ),
385 };
386 async move {
387 let out = self.send(&pdu).await;
388 let _ = self.close().await;
389 out
390 }
391 }
392 }
393}
394
395pub trait SyncAssociation<S: std::io::Read + std::io::Write + CloseSocket>:
397 private::SyncAssociationSealed<S> + Association
398{
399 fn inner_stream(&mut self) -> &mut S;
409
410 fn get_mut(&mut self) -> (&mut S, &mut BytesMut);
412
413 fn send(&mut self, pdu: &Pdu) -> Result<()> {
415 private::SyncAssociationSealed::send(self, pdu)
416 }
417
418 fn receive(&mut self) -> Result<Pdu> {
420 private::SyncAssociationSealed::receive(self)
421 }
422
423 fn abort(mut self) -> Result<()>
427 where
428 Self: Sized,
429 {
430 private::SyncAssociationSealed::abort(&mut self)
431 }
432
433 fn release(mut self) -> Result<()>
443 where
444 Self: Sized,
445 {
446 private::SyncAssociationSealed::release(&mut self)
447 }
448
449 fn send_pdata(&mut self, presentation_context_id: u8) -> PDataWriter<&mut S> {
455 let max_pdu_length = self.peer_max_pdu_length();
456 PDataWriter::new(self.inner_stream(), presentation_context_id, max_pdu_length)
457 }
458
459 fn receive_pdata(&mut self) -> PDataReader<'_, &mut S> {
465 let max_pdu_length = self.local_max_pdu_length();
466 let (socket, read_buffer) = self.get_mut();
467 PDataReader::new(socket, max_pdu_length, read_buffer)
468 }
469}
470
471#[cfg(feature = "async")]
472pub trait AsyncAssociation<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin>:
474 private::AsyncAssociationSealed<S> + Association
475{
476 fn inner_stream(&mut self) -> &mut S;
486
487 fn get_mut(&mut self) -> (&mut S, &mut BytesMut);
489
490 fn send(&mut self, pdu: &Pdu) -> impl std::future::Future<Output = Result<()>> + Send
492 where
493 Self: Send,
494 {
495 async move { private::AsyncAssociationSealed::send(self, pdu).await }
496 }
497
498 fn receive(&mut self) -> impl std::future::Future<Output = Result<Pdu>> + Send
500 where
501 Self: Send,
502 {
503 async move { private::AsyncAssociationSealed::receive(self).await }
504 }
505
506 fn abort(mut self) -> impl std::future::Future<Output = Result<()>> + Send
510 where
511 Self: Sized + Send,
512 {
513 async move { private::AsyncAssociationSealed::abort(&mut self).await }
514 }
515
516 fn release(mut self) -> impl std::future::Future<Output = Result<()>> + Send
526 where
527 Self: Sized + Send,
528 {
529 async move { private::AsyncAssociationSealed::release(&mut self).await }
530 }
531
532 fn send_pdata(&mut self, presentation_context_id: u8) -> AsyncPDataWriter<&mut S> {
538 let max_pdu_length = self.peer_max_pdu_length();
539 AsyncPDataWriter::new(self.inner_stream(), presentation_context_id, max_pdu_length)
540 }
541
542 fn receive_pdata(&mut self) -> PDataReader<'_, &mut S> {
548 let max_pdu_length = self.local_max_pdu_length();
549 let (socket, read_buffer) = self.get_mut();
550 PDataReader::new(socket, max_pdu_length, read_buffer)
551 }
552}
553
554#[cfg(feature = "async")]
556async fn timeout<T>(
557 timeout: Option<Duration>,
558 block: impl std::future::Future<Output = Result<T>>,
559) -> Result<T> {
560 if let Some(timeout) = timeout {
561 tokio::time::timeout(timeout, block)
562 .await
563 .map_err(|_| std::io::Error::from(std::io::ErrorKind::TimedOut))
564 .context(crate::association::TimeoutSnafu)?
565 } else {
566 block.await
567 }
568}
569
570pub(crate) fn encode_pdu(buffer: &mut Vec<u8>, pdu: &Pdu, peer_max_pdu_length: u32) -> Result<()> {
572 write_pdu(buffer, pdu).context(SendPduSnafu)?;
573 if buffer.len() > peer_max_pdu_length as usize {
574 return SendTooLongPduSnafu {
575 length: buffer.len(),
576 }
577 .fail();
578 }
579 Ok(())
580}
581
582pub fn read_pdu_from_wire<R>(
588 reader: &mut R,
589 read_buffer: &mut BytesMut,
590 max_pdu_length: u32,
591 strict: bool,
592) -> Result<Pdu>
593where
594 R: Read,
595{
596 let mut reader = BufReader::new(reader);
597 let msg = loop {
598 let mut buf = Cursor::new(&read_buffer[..]);
599 match pdu::read_pdu(&mut buf, max_pdu_length, strict).context(ReceivePduSnafu)? {
601 Some(pdu) => {
602 read_buffer.advance(buf.position() as usize);
603 break pdu;
604 }
605 None => {
606 buf.set_position(0)
608 }
609 }
610 let recv = reader
612 .fill_buf()
613 .context(ReadPduSnafu)
614 .context(ReceivePduSnafu)?;
615 let bytes_read = recv.len();
616 read_buffer.extend_from_slice(recv);
617 reader.consume(bytes_read);
618 ensure!(bytes_read != 0, ConnectionClosedSnafu);
619 };
620 Ok(msg)
621}
622
623#[cfg(feature = "async")]
629pub async fn read_pdu_from_wire_async<R: tokio::io::AsyncRead + Unpin>(
630 reader: &mut R,
631 read_buffer: &mut BytesMut,
632 max_pdu_length: u32,
633 strict: bool,
634) -> Result<Pdu> {
635 use tokio::io::AsyncReadExt;
636 let msg = loop {
639 let mut buf = Cursor::new(&read_buffer[..]);
640 match pdu::read_pdu(&mut buf, max_pdu_length, strict).context(ReceivePduSnafu)? {
641 Some(pdu) => {
642 read_buffer.advance(buf.position() as usize);
643 break pdu;
644 }
645 None => {
646 buf.set_position(0)
648 }
649 }
650 let recv = reader
651 .read_buf(read_buffer)
652 .await
653 .context(ReadPduSnafu)
654 .context(ReceivePduSnafu)?;
655 ensure!(recv > 0, ConnectionClosedSnafu);
656 };
657 Ok(msg)
658}