1use bytes::BytesMut;
8use std::{
9 borrow::Cow,
10 convert::TryInto,
11 net::{TcpStream, ToSocketAddrs},
12 time::Duration,
13};
14
15#[cfg(feature = "async")]
16use crate::association::AsyncAssociation;
17use crate::{
18 association::{
19 encode_pdu, private::SyncAssociationSealed, read_pdu_from_wire, Association,
20 NegotiatedOptions, SocketOptions, SyncAssociation,
21 },
22 pdu::{
23 write_pdu, AbortRQSource, AssociationAC, AssociationRQ, Pdu, PresentationContextNegotiated,
24 PresentationContextProposed, PresentationContextResultReason, UserIdentity,
25 UserIdentityType, UserVariableItem, DEFAULT_MAX_PDU, LARGE_PDU_SIZE, PDU_HEADER_SIZE,
26 },
27 AeAddr, IMPLEMENTATION_CLASS_UID, IMPLEMENTATION_VERSION_NAME,
28};
29use snafu::{ensure, ResultExt};
30
31use super::{uid::trim_uid, Result};
32
33#[deprecated(since = "0.9.1")]
35pub mod non_blocking {}
36
37#[cfg(feature = "sync-tls")]
38pub type TlsStream = rustls::StreamOwned<rustls::ClientConnection, std::net::TcpStream>;
39#[cfg(feature = "async-tls")]
40pub type AsyncTlsStream = tokio_rustls::client::TlsStream<tokio::net::TcpStream>;
41
42pub use crate::association::CloseSocket;
43
44fn tcp_connection<T>(ae_address: &AeAddr<T>, opts: &SocketOptions) -> Result<TcpStream>
46where
47 T: ToSocketAddrs,
48{
49 let conn_result: Result<TcpStream> = if let Some(timeout) = opts.connection_timeout {
52 let addresses = ae_address
53 .to_socket_addrs()
54 .context(super::ToAddressSnafu)?;
55 let mut result = Result::Err(std::io::Error::from(std::io::ErrorKind::AddrNotAvailable));
56 for address in addresses {
57 result = TcpStream::connect_timeout(&address, timeout);
58 if result.is_ok() {
59 break;
60 }
61 }
62 result.context(super::ConnectSnafu)
63 } else {
64 TcpStream::connect(ae_address).context(super::ConnectSnafu)
65 };
66
67 let socket = conn_result?;
68 socket
69 .set_read_timeout(opts.read_timeout)
70 .context(super::SetReadTimeoutSnafu)?;
71 socket
72 .set_write_timeout(opts.write_timeout)
73 .context(super::SetWriteTimeoutSnafu)?;
74
75 Ok(socket)
76}
77
78#[cfg(feature = "sync-tls")]
80fn tls_connection<T>(
81 ae_address: &AeAddr<T>,
82 server_name: &str,
83 opts: &SocketOptions,
84 tls_config: std::sync::Arc<rustls::ClientConfig>,
85) -> Result<TlsStream>
86where
87 T: ToSocketAddrs,
88{
89 use std::convert::TryFrom;
90
91 let socket = tcp_connection(ae_address, opts)?;
92 let server_name = rustls::pki_types::ServerName::try_from(server_name.to_string())
93 .context(super::InvalidServerNameSnafu)?;
94
95 let conn = rustls::ClientConnection::new(tls_config.clone(), server_name)
96 .context(super::TlsConnectionSnafu)?;
97
98 Ok(rustls::StreamOwned::new(conn, socket))
99}
100
101#[derive(Debug, Clone)]
241pub struct ClientAssociationOptions<'a> {
242 calling_ae_title: Cow<'a, str>,
244 called_ae_title: Option<Cow<'a, str>>,
246 application_context_name: Cow<'a, str>,
248 presentation_contexts: Vec<(Cow<'a, str>, Vec<Cow<'a, str>>)>,
250 protocol_version: u16,
252 max_pdu_length: u32,
254 strict: bool,
256 username: Option<Cow<'a, str>>,
258 password: Option<Cow<'a, str>>,
260 kerberos_service_ticket: Option<Cow<'a, str>>,
262 saml_assertion: Option<Cow<'a, str>>,
264 jwt: Option<Cow<'a, str>>,
266 socket_options: SocketOptions,
268 #[cfg(feature = "sync-tls")]
270 tls_config: Option<std::sync::Arc<rustls::ClientConfig>>,
271 #[cfg(feature = "sync-tls")]
273 server_name: Option<String>,
274}
275
276impl Default for ClientAssociationOptions<'_> {
277 fn default() -> Self {
278 ClientAssociationOptions {
279 calling_ae_title: "THIS-SCU".into(),
281 called_ae_title: None,
283 application_context_name: "1.2.840.10008.3.1.1.1".into(),
285 presentation_contexts: Vec::new(),
287 protocol_version: 1,
288 max_pdu_length: DEFAULT_MAX_PDU,
289 strict: true,
290 username: None,
291 password: None,
292 kerberos_service_ticket: None,
293 saml_assertion: None,
294 jwt: None,
295 socket_options: SocketOptions {
296 read_timeout: None,
297 write_timeout: None,
298 connection_timeout: None,
299 },
300 #[cfg(feature = "sync-tls")]
301 tls_config: None,
302 #[cfg(feature = "sync-tls")]
303 server_name: None,
304 }
305 }
306}
307
308impl<'a> ClientAssociationOptions<'a> {
309 pub fn new() -> Self {
311 Self::default()
312 }
313 pub fn calling_ae_title<T>(mut self, calling_ae_title: T) -> Self
318 where
319 T: Into<Cow<'a, str>>,
320 {
321 self.calling_ae_title = calling_ae_title.into();
322 self
323 }
324
325 pub fn called_ae_title<T>(mut self, called_ae_title: T) -> Self
332 where
333 T: Into<Cow<'a, str>>,
334 {
335 let cae = called_ae_title.into();
336 if cae.is_empty() {
337 self.called_ae_title = None;
338 } else {
339 self.called_ae_title = Some(cae);
340 }
341 self
342 }
343
344 pub fn with_presentation_context<T>(
347 mut self,
348 abstract_syntax_uid: T,
349 transfer_syntax_uids: Vec<T>,
350 ) -> Self
351 where
352 T: Into<Cow<'a, str>>,
353 {
354 let transfer_syntaxes: Vec<Cow<'a, str>> = transfer_syntax_uids
355 .into_iter()
356 .map(|t| trim_uid(t.into()))
357 .collect();
358 self.presentation_contexts
359 .push((trim_uid(abstract_syntax_uid.into()), transfer_syntaxes));
360 self
361 }
362
363 pub fn with_abstract_syntax<T>(self, abstract_syntax_uid: T) -> Self
367 where
368 T: Into<Cow<'a, str>>,
369 {
370 let default_transfer_syntaxes: Vec<Cow<'a, str>> =
371 vec!["1.2.840.10008.1.2.1".into(), "1.2.840.10008.1.2".into()];
372 self.with_presentation_context(abstract_syntax_uid.into(), default_transfer_syntaxes)
373 }
374
375 pub fn max_pdu_length(mut self, value: u32) -> Self {
378 self.max_pdu_length = value;
379 self
380 }
381
382 pub fn strict(mut self, strict: bool) -> Self {
386 self.strict = strict;
387 self
388 }
389
390 pub fn username<T>(mut self, username: T) -> Self
392 where
393 T: Into<Cow<'a, str>>,
394 {
395 let username = username.into();
396 if username.is_empty() {
397 self.username = None;
398 } else {
399 self.username = Some(username);
400 self.saml_assertion = None;
401 self.jwt = None;
402 self.kerberos_service_ticket = None;
403 }
404 self
405 }
406
407 pub fn password<T>(mut self, password: T) -> Self
409 where
410 T: Into<Cow<'a, str>>,
411 {
412 let password = password.into();
413 if password.is_empty() {
414 self.password = None;
415 } else {
416 self.password = Some(password);
417 self.saml_assertion = None;
418 self.jwt = None;
419 self.kerberos_service_ticket = None;
420 }
421 self
422 }
423
424 pub fn username_password<T, U>(mut self, username: T, password: U) -> Self
426 where
427 T: Into<Cow<'a, str>>,
428 U: Into<Cow<'a, str>>,
429 {
430 let username = username.into();
431 let password = password.into();
432 if username.is_empty() {
433 self.username = None;
434 self.password = None;
435 } else {
436 self.username = Some(username);
437 self.password = Some(password);
438 self.saml_assertion = None;
439 self.jwt = None;
440 self.kerberos_service_ticket = None;
441 }
442 self
443 }
444
445 pub fn kerberos_service_ticket<T>(mut self, kerberos_service_ticket: T) -> Self
447 where
448 T: Into<Cow<'a, str>>,
449 {
450 let kerberos_service_ticket = kerberos_service_ticket.into();
451 if kerberos_service_ticket.is_empty() {
452 self.kerberos_service_ticket = None;
453 } else {
454 self.kerberos_service_ticket = Some(kerberos_service_ticket);
455 self.username = None;
456 self.password = None;
457 self.saml_assertion = None;
458 self.jwt = None;
459 }
460 self
461 }
462
463 pub fn saml_assertion<T>(mut self, saml_assertion: T) -> Self
465 where
466 T: Into<Cow<'a, str>>,
467 {
468 let saml_assertion = saml_assertion.into();
469 if saml_assertion.is_empty() {
470 self.saml_assertion = None;
471 } else {
472 self.saml_assertion = Some(saml_assertion);
473 self.username = None;
474 self.password = None;
475 self.jwt = None;
476 self.kerberos_service_ticket = None;
477 }
478 self
479 }
480
481 pub fn jwt<T>(mut self, jwt: T) -> Self
483 where
484 T: Into<Cow<'a, str>>,
485 {
486 let jwt = jwt.into();
487 if jwt.is_empty() {
488 self.jwt = None;
489 } else {
490 self.jwt = Some(jwt);
491 self.username = None;
492 self.password = None;
493 self.saml_assertion = None;
494 self.kerberos_service_ticket = None;
495 }
496 self
497 }
498
499 #[cfg(feature = "sync-tls")]
501 pub fn tls_config(mut self, config: impl Into<std::sync::Arc<rustls::ClientConfig>>) -> Self {
502 self.tls_config = Some(config.into());
503 self
504 }
505
506 #[cfg(feature = "sync-tls")]
508 pub fn server_name(mut self, server_name: &str) -> Self {
509 self.server_name = Some(server_name.to_string());
510 self
511 }
512
513 pub fn establish<A: ToSocketAddrs>(
517 self,
518 address: A,
519 ) -> Result<ClientAssociation<std::net::TcpStream>> {
520 let addr = AeAddr::new_socket_addr(address);
521 let socket = tcp_connection(&addr, &self.socket_options)?;
522 self.establish_impl(addr, socket)
523 }
524
525 #[cfg(feature = "sync-tls")]
529 pub fn establish_tls<A: ToSocketAddrs>(
530 self,
531 address: A,
532 ) -> Result<ClientAssociation<TlsStream>> {
533 match (&self.tls_config, &self.server_name) {
534 (Some(tls_config), Some(server_name)) => {
535 let addr = AeAddr::new_socket_addr(address);
536 let socket =
537 tls_connection(&addr, server_name, &self.socket_options, tls_config.clone())?;
538 self.establish_impl(addr, socket)
539 }
540 _ => super::TlsConfigMissingSnafu.fail()?,
541 }
542 }
543
544 #[allow(unreachable_patterns)]
568 pub fn establish_with(self, ae_address: &str) -> Result<ClientAssociation<TcpStream>> {
569 match ae_address.try_into() {
570 Ok(ae_address) => {
571 let socket = tcp_connection(&ae_address, &self.socket_options)?;
572 self.establish_impl(ae_address, socket)
573 }
574 Err(_) => {
575 let addr = AeAddr::new_socket_addr(ae_address);
576 let socket = tcp_connection(&addr, &self.socket_options)?;
577 self.establish_impl(addr, socket)
578 }
579 }
580 }
581
582 #[allow(unreachable_patterns)]
606 #[cfg(feature = "sync-tls")]
607 pub fn establish_with_tls(self, ae_address: &str) -> Result<ClientAssociation<TlsStream>> {
608 match (&self.tls_config, &self.server_name) {
609 (Some(tls_config), Some(server_name)) => match ae_address.try_into() {
610 Ok(ae_address) => {
611 let socket = tls_connection(
612 &ae_address,
613 server_name,
614 &self.socket_options,
615 tls_config.clone(),
616 )?;
617 self.establish_impl(ae_address, socket)
618 }
619 Err(_) => {
620 let addr = AeAddr::new_socket_addr(ae_address);
621 let socket = tls_connection(
622 &addr,
623 server_name,
624 &self.socket_options,
625 tls_config.clone(),
626 )?;
627 self.establish_impl(addr, socket)
628 }
629 },
630 _ => super::TlsConfigMissingSnafu.fail()?,
631 }
632 }
633
634 pub fn read_timeout(self, timeout: Duration) -> Self {
638 Self {
639 socket_options: SocketOptions {
640 read_timeout: Some(timeout),
641 write_timeout: self.socket_options.write_timeout,
642 connection_timeout: self.socket_options.connection_timeout,
643 },
644 ..self
645 }
646 }
647
648 pub fn write_timeout(self, timeout: Duration) -> Self {
650 Self {
651 socket_options: SocketOptions {
652 read_timeout: self.socket_options.read_timeout,
653 write_timeout: Some(timeout),
654 connection_timeout: self.socket_options.connection_timeout,
655 },
656 ..self
657 }
658 }
659
660 pub fn connection_timeout(self, timeout: Duration) -> Self {
662 Self {
663 socket_options: SocketOptions {
664 read_timeout: self.socket_options.read_timeout,
665 write_timeout: self.socket_options.write_timeout,
666 connection_timeout: Some(timeout),
667 },
668 ..self
669 }
670 }
671
672 fn create_a_associate_req(
674 &'a self,
675 ae_title: Option<&str>,
676 ) -> Result<(Vec<PresentationContextProposed>, Pdu)> {
677 let ClientAssociationOptions {
678 calling_ae_title,
679 called_ae_title,
680 application_context_name,
681 presentation_contexts,
682 protocol_version,
683 max_pdu_length,
684 username,
685 password,
686 kerberos_service_ticket,
687 saml_assertion,
688 jwt,
689 ..
690 } = self;
691 ensure!(
694 !presentation_contexts.is_empty(),
695 crate::association::MissingAbstractSyntaxSnafu
696 );
697
698 let called_ae_title: &str = match (&called_ae_title, ae_title) {
700 (Some(aec), Some(aet)) => {
701 if aec != aet {
702 tracing::warn!(
703 "Option `called_ae_title` overrides the AE title from `{aet}` to `{aec}`"
704 );
705 }
706 aec
707 }
708 (Some(aec), None) => aec,
709 (None, Some(aec)) => aec,
710 (None, None) => "ANY-SCP",
711 };
712
713 let presentation_contexts_proposed: Vec<_> = presentation_contexts
714 .iter()
715 .enumerate()
716 .map(|(i, presentation_context)| PresentationContextProposed {
717 id: (2 * i + 1) as u8,
718 abstract_syntax: presentation_context.0.to_string(),
719 transfer_syntaxes: presentation_context
720 .1
721 .iter()
722 .map(|uid| uid.to_string())
723 .collect(),
724 })
725 .collect();
726
727 let mut user_variables = vec![
728 UserVariableItem::MaxLength(*max_pdu_length),
729 UserVariableItem::ImplementationClassUID(IMPLEMENTATION_CLASS_UID.to_string()),
730 UserVariableItem::ImplementationVersionName(IMPLEMENTATION_VERSION_NAME.to_string()),
731 ];
732
733 if let Some(user_identity) = Self::determine_user_identity(
734 username.as_deref(),
735 password.as_deref(),
736 kerberos_service_ticket.as_deref(),
737 saml_assertion.as_deref(),
738 jwt.as_deref(),
739 ) {
740 user_variables.push(UserVariableItem::UserIdentityItem(user_identity));
741 }
742
743 Ok((
744 presentation_contexts_proposed.clone(),
745 Pdu::AssociationRQ(AssociationRQ {
746 protocol_version: *protocol_version,
747 calling_ae_title: calling_ae_title.to_string(),
748 called_ae_title: called_ae_title.to_string(),
749 application_context_name: application_context_name.to_string(),
750 presentation_contexts: presentation_contexts_proposed,
751 user_variables,
752 }),
753 ))
754 }
755
756 fn process_a_association_resp(
760 &self,
761 msg: Pdu,
762 presentation_contexts_proposed: &[PresentationContextProposed],
763 ) -> Result<NegotiatedOptions> {
764 match msg {
765 Pdu::AssociationAC(AssociationAC {
766 protocol_version: protocol_version_scp,
767 application_context_name: _,
768 presentation_contexts: presentation_contexts_scp,
769 calling_ae_title: _,
770 called_ae_title,
771 user_variables,
772 }) => {
773 ensure!(
774 self.protocol_version == protocol_version_scp,
775 crate::association::ProtocolVersionMismatchSnafu {
776 expected: self.protocol_version,
777 got: protocol_version_scp,
778 }
779 );
780
781 let acceptor_max_pdu_length = user_variables
782 .iter()
783 .find_map(|item| match item {
784 UserVariableItem::MaxLength(len) => Some(*len),
785 _ => None,
786 })
787 .unwrap_or(DEFAULT_MAX_PDU);
788
789 let acceptor_max_pdu_length = if acceptor_max_pdu_length == 0 {
791 u32::MAX
792 } else {
793 acceptor_max_pdu_length
794 };
795
796 let presentation_contexts: Vec<_> = presentation_contexts_scp
797 .into_iter()
798 .filter(|c| {
799 c.reason == PresentationContextResultReason::Acceptance
800 && presentation_contexts_proposed.iter().any(|p| p.id == c.id)
801 })
802 .map(|c| {
803 let pcp = presentation_contexts_proposed
804 .iter()
805 .find(|pc| pc.id == c.id)
806 .unwrap();
807 PresentationContextNegotiated {
808 id: c.id,
809 reason: c.reason,
810 transfer_syntax: c.transfer_syntax,
811 abstract_syntax: pcp.abstract_syntax.clone(),
812 }
813 })
814 .collect();
815 if presentation_contexts.is_empty() {
816 return crate::association::NoAcceptedPresentationContextsSnafu.fail();
817 }
818 Ok(NegotiatedOptions {
819 presentation_contexts,
820 peer_max_pdu_length: acceptor_max_pdu_length,
821 user_variables,
822 peer_ae_title: called_ae_title,
823 })
824 }
825 Pdu::AssociationRJ(association_rj) => {
826 crate::association::RejectedSnafu { association_rj }.fail()
827 }
828 pdu @ Pdu::AbortRQ { .. }
829 | pdu @ Pdu::ReleaseRQ
830 | pdu @ Pdu::AssociationRQ { .. }
831 | pdu @ Pdu::PData { .. }
832 | pdu @ Pdu::ReleaseRP => crate::association::UnexpectedPduSnafu { pdu }.fail(),
833 pdu @ Pdu::Unknown { .. } => crate::association::UnknownPduSnafu { pdu }.fail(),
834 }
835 }
836
837 fn establish_impl<T, S>(
839 self,
840 ae_address: AeAddr<T>,
841 mut socket: S,
842 ) -> Result<ClientAssociation<S>>
843 where
844 T: ToSocketAddrs,
845 S: CloseSocket + std::io::Read + std::io::Write,
846 {
847 let (pc_proposed, a_associate) = self.create_a_associate_req(ae_address.ae_title())?;
848 let mut buffer: Vec<u8> = Vec::with_capacity(self.max_pdu_length as usize);
849
850 write_pdu(&mut buffer, &a_associate).context(super::SendPduSnafu)?;
851 socket.write_all(&buffer).context(super::WireSendSnafu)?;
852 buffer.clear();
853
854 let mut buf = BytesMut::with_capacity(
855 (self.max_pdu_length.min(LARGE_PDU_SIZE) + PDU_HEADER_SIZE) as usize,
856 );
857 let resp = read_pdu_from_wire(&mut socket, &mut buf, self.max_pdu_length, self.strict)?;
858 let negotiated_options = self.process_a_association_resp(resp, &pc_proposed);
859 match negotiated_options {
860 Err(e) => {
861 let _ = write_pdu(
863 &mut buffer,
864 &Pdu::AbortRQ {
865 source: AbortRQSource::ServiceUser,
866 },
867 );
868 let _ = socket.write_all(&buffer);
869 buffer.clear();
870 Err(e)
871 }
872 Ok(NegotiatedOptions {
873 presentation_contexts,
874 peer_max_pdu_length,
875 user_variables,
876 peer_ae_title,
877 }) => {
878 Ok(ClientAssociation {
879 presentation_contexts,
880 requestor_max_pdu_length: self.max_pdu_length,
881 acceptor_max_pdu_length: peer_max_pdu_length,
882 socket,
883 write_buffer: buffer,
884 strict: self.strict,
885 read_buffer: buf,
887 read_timeout: self.socket_options.read_timeout,
888 write_timeout: self.socket_options.write_timeout,
889 user_variables,
890 peer_ae_title,
891 })
892 }
893 }
894 }
895
896 fn determine_user_identity<T>(
897 username: Option<T>,
898 password: Option<T>,
899 kerberos_service_ticket: Option<T>,
900 saml_assertion: Option<T>,
901 jwt: Option<T>,
902 ) -> Option<UserIdentity>
903 where
904 T: Into<Cow<'a, str>>,
905 {
906 if let Some(username) = username {
907 if let Some(password) = password {
908 return Some(UserIdentity::new(
909 false,
910 UserIdentityType::UsernamePassword,
911 username.into().as_bytes().to_vec(),
912 password.into().as_bytes().to_vec(),
913 ));
914 } else {
915 return Some(UserIdentity::new(
916 false,
917 UserIdentityType::Username,
918 username.into().as_bytes().to_vec(),
919 vec![],
920 ));
921 }
922 }
923
924 if let Some(kerberos_service_ticket) = kerberos_service_ticket {
925 return Some(UserIdentity::new(
926 false,
927 UserIdentityType::KerberosServiceTicket,
928 kerberos_service_ticket.into().as_bytes().to_vec(),
929 vec![],
930 ));
931 }
932
933 if let Some(saml_assertion) = saml_assertion {
934 return Some(UserIdentity::new(
935 false,
936 UserIdentityType::SamlAssertion,
937 saml_assertion.into().as_bytes().to_vec(),
938 vec![],
939 ));
940 }
941
942 if let Some(jwt) = jwt {
943 return Some(UserIdentity::new(
944 false,
945 UserIdentityType::Jwt,
946 jwt.into().as_bytes().to_vec(),
947 vec![],
948 ));
949 }
950
951 None
952 }
953}
954
955#[derive(Debug)]
970pub struct ClientAssociation<S> {
971 presentation_contexts: Vec<PresentationContextNegotiated>,
974 requestor_max_pdu_length: u32,
976 acceptor_max_pdu_length: u32,
978 socket: S,
980 write_buffer: Vec<u8>,
982 strict: bool,
984 read_timeout: Option<Duration>,
986 write_timeout: Option<Duration>,
988 read_buffer: BytesMut,
990 user_variables: Vec<UserVariableItem>,
992 peer_ae_title: String,
994}
995
996impl<S> Association for ClientAssociation<S>
997where
998 S: CloseSocket + std::io::Read + std::io::Write,
999{
1000 fn peer_ae_title(&self) -> &str {
1001 &self.peer_ae_title
1002 }
1003
1004 fn acceptor_max_pdu_length(&self) -> u32 {
1007 self.acceptor_max_pdu_length
1008 }
1009
1010 fn requestor_max_pdu_length(&self) -> u32 {
1013 self.requestor_max_pdu_length
1014 }
1015
1016 fn local_max_pdu_length(&self) -> u32 {
1019 self.requestor_max_pdu_length
1020 }
1021
1022 fn peer_max_pdu_length(&self) -> u32 {
1025 self.acceptor_max_pdu_length
1026 }
1027
1028 fn presentation_contexts(&self) -> &[PresentationContextNegotiated] {
1029 &self.presentation_contexts
1030 }
1031
1032 fn user_variables(&self) -> &[UserVariableItem] {
1033 &self.user_variables
1034 }
1035}
1036
1037impl<S> ClientAssociation<S>
1038where
1039 S: CloseSocket + std::io::Read + std::io::Write,
1040{
1041 pub fn read_timeout(&self) -> Option<Duration> {
1043 self.read_timeout
1044 }
1045
1046 pub fn write_timeout(&self) -> Option<Duration> {
1048 self.write_timeout
1049 }
1050
1051 pub fn acceptor_max_pdu_length(&self) -> u32 {
1054 self.acceptor_max_pdu_length
1055 }
1056
1057 pub fn requestor_max_pdu_length(&self) -> u32 {
1060 self.requestor_max_pdu_length
1061 }
1062
1063 pub fn user_variables(&self) -> &[UserVariableItem] {
1068 &self.user_variables
1069 }
1070
1071 pub fn presentation_contexts(&self) -> &[PresentationContextNegotiated] {
1073 &self.presentation_contexts
1074 }
1075}
1076
1077impl<S> ClientAssociation<S>
1079where
1080 S: CloseSocket + std::io::Read + std::io::Write,
1081{
1082 pub fn send(&mut self, pdu: &Pdu) -> Result<()> {
1084 SyncAssociation::send(self, pdu)
1085 }
1086
1087 pub fn receive(&mut self) -> Result<Pdu> {
1089 SyncAssociation::receive(self)
1090 }
1091
1092 pub fn send_pdata(
1098 &mut self,
1099 presentation_context_id: u8,
1100 ) -> crate::association::pdata::PDataWriter<&mut S> {
1101 SyncAssociation::send_pdata(self, presentation_context_id)
1102 }
1103
1104 pub fn release(self) -> Result<()> {
1114 SyncAssociation::release(self)
1115 }
1116
1117 pub fn abort(self) -> Result<()> {
1121 SyncAssociation::abort(self)
1122 }
1123
1124 pub fn receive_pdata(&mut self) -> crate::association::pdata::PDataReader<'_, &mut S> {
1130 SyncAssociation::receive_pdata(self)
1131 }
1132
1133 pub fn inner_stream(&mut self) -> &mut S {
1143 SyncAssociation::inner_stream(self)
1144 }
1145}
1146
1147impl<S> SyncAssociationSealed<S> for ClientAssociation<S>
1148where
1149 S: CloseSocket + std::io::Read + std::io::Write,
1150{
1151 fn send(&mut self, pdu: &Pdu) -> Result<()> {
1153 self.write_buffer.clear();
1154 encode_pdu(
1155 &mut self.write_buffer,
1156 pdu,
1157 self.acceptor_max_pdu_length + PDU_HEADER_SIZE,
1158 )?;
1159 self.socket
1160 .write_all(&self.write_buffer)
1161 .context(super::WireSendSnafu)
1162 }
1163
1164 fn receive(&mut self) -> Result<Pdu> {
1166 read_pdu_from_wire(
1167 &mut self.socket,
1168 &mut self.read_buffer,
1169 self.requestor_max_pdu_length,
1170 self.strict,
1171 )
1172 }
1173
1174 fn close(&mut self) -> std::io::Result<()> {
1175 self.socket.close()
1176 }
1177}
1178
1179impl<S> SyncAssociation<S> for ClientAssociation<S>
1180where
1181 S: CloseSocket + std::io::Read + std::io::Write,
1182{
1183 fn inner_stream(&mut self) -> &mut S {
1184 &mut self.socket
1185 }
1186
1187 fn get_mut(&mut self) -> (&mut S, &mut BytesMut) {
1188 let Self {
1189 socket,
1190 read_buffer,
1191 ..
1192 } = self;
1193 (socket, read_buffer)
1194 }
1195}
1196
1197#[deprecated(since = "0.9.1", note = "Call `SyncAssociation::release` instead")]
1199pub trait Release {
1200 #[deprecated(since = "0.9.1", note = "Call `SyncAssociation::release` instead")]
1201 fn release(&mut self) -> Result<()>;
1202}
1203
1204#[allow(deprecated)]
1205impl Release for ClientAssociation<std::net::TcpStream> {
1206 fn release(&mut self) -> Result<()> {
1207 SyncAssociationSealed::release(self)
1208 }
1209}
1210
1211#[cfg(feature = "async")]
1212pub(crate) async fn async_connection<T>(
1214 ae_address: &AeAddr<T>,
1215 opts: &SocketOptions,
1216) -> Result<tokio::net::TcpStream>
1217where
1218 T: tokio::net::ToSocketAddrs,
1219{
1220 super::timeout(opts.connection_timeout, async {
1221 tokio::net::TcpStream::connect(ae_address.socket_addr())
1222 .await
1223 .context(crate::association::ConnectSnafu)
1224 })
1225 .await
1226}
1227
1228#[cfg(feature = "async-tls")]
1230pub(crate) async fn async_tls_connection<T>(
1231 ae_address: &AeAddr<T>,
1232 server_name: &str,
1233 opts: &SocketOptions,
1234 tls_config: std::sync::Arc<rustls::ClientConfig>,
1235) -> Result<AsyncTlsStream>
1236where
1237 T: tokio::net::ToSocketAddrs,
1238{
1239 use rustls::pki_types::ServerName;
1240 use std::convert::TryFrom;
1241
1242 let tcp_stream = async_connection(ae_address, opts).await?;
1243 let connector = tokio_rustls::TlsConnector::from(tls_config);
1244 let domain = ServerName::try_from(server_name.to_string())
1245 .context(crate::association::InvalidServerNameSnafu)?;
1246 let tls_stream = connector
1249 .connect(domain, tcp_stream)
1250 .await
1251 .context(crate::association::ConnectSnafu)?;
1252 Ok(tls_stream)
1253}
1254
1255#[cfg(feature = "async")]
1269#[derive(Debug)]
1270pub struct AsyncClientAssociation<S> {
1271 presentation_contexts: Vec<PresentationContextNegotiated>,
1274 requestor_max_pdu_length: u32,
1276 acceptor_max_pdu_length: u32,
1278 socket: S,
1280 write_buffer: Vec<u8>,
1282 strict: bool,
1284 read_timeout: Option<Duration>,
1286 write_timeout: Option<Duration>,
1288 read_buffer: BytesMut,
1290 user_variables: Vec<UserVariableItem>,
1292 peer_ae_title: String,
1294}
1295
1296#[cfg(feature = "async")]
1297impl<'a> ClientAssociationOptions<'a> {
1298 async fn establish_impl_async<T, S>(
1299 self,
1300 ae_address: AeAddr<T>,
1301 mut socket: S,
1302 ) -> Result<AsyncClientAssociation<S>>
1303 where
1304 T: tokio::net::ToSocketAddrs,
1305 S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send,
1306 {
1307 use tokio::io::AsyncWriteExt;
1308 let (pc_proposed, a_associate) = self.create_a_associate_req(ae_address.ae_title())?;
1309 let mut write_buffer: Vec<u8> = Vec::with_capacity(DEFAULT_MAX_PDU as usize);
1310
1311 write_pdu(&mut write_buffer, &a_associate).context(crate::association::SendPduSnafu)?;
1313 super::timeout(self.socket_options.write_timeout, async {
1314 socket
1315 .write_all(&write_buffer)
1316 .await
1317 .context(crate::association::WireSendSnafu)?;
1318 Ok(())
1319 })
1320 .await?;
1321 write_buffer.clear();
1322
1323 let mut read_buffer = BytesMut::with_capacity(
1325 (self.max_pdu_length.min(LARGE_PDU_SIZE) + PDU_HEADER_SIZE) as usize,
1326 );
1327 let resp = super::timeout(self.socket_options.read_timeout, async {
1328 super::read_pdu_from_wire_async(
1329 &mut socket,
1330 &mut read_buffer,
1331 self.max_pdu_length,
1332 self.strict,
1333 )
1334 .await
1335 })
1336 .await?;
1337 let negotiated_options = self.process_a_association_resp(resp, &pc_proposed);
1338 match negotiated_options {
1339 Err(e) => {
1340 let _ = write_pdu(
1342 &mut write_buffer,
1343 &Pdu::AbortRQ {
1344 source: AbortRQSource::ServiceUser,
1345 },
1346 );
1347 socket
1348 .write_all(&write_buffer)
1349 .await
1350 .context(crate::association::WireSendSnafu)?;
1351 write_buffer.clear();
1352 Err(e)
1353 }
1354 Ok(NegotiatedOptions {
1355 presentation_contexts,
1356 peer_max_pdu_length,
1357 user_variables,
1358 peer_ae_title,
1359 }) => {
1360 Ok(AsyncClientAssociation {
1361 presentation_contexts,
1362 requestor_max_pdu_length: self.max_pdu_length,
1363 acceptor_max_pdu_length: peer_max_pdu_length,
1364 socket,
1365 write_buffer,
1366 strict: self.strict,
1367 read_buffer,
1369 read_timeout: self.socket_options.read_timeout,
1370 write_timeout: self.socket_options.write_timeout,
1371 user_variables,
1372 peer_ae_title,
1373 })
1374 }
1375 }
1376 }
1377
1378 pub async fn establish_async<A: tokio::net::ToSocketAddrs>(
1382 self,
1383 address: A,
1384 ) -> Result<AsyncClientAssociation<tokio::net::TcpStream>> {
1385 let addr = AeAddr::new_socket_addr(address);
1386 let socket = async_connection(&addr, &self.socket_options).await?;
1387 self.establish_impl_async(addr, socket).await
1388 }
1389
1390 #[cfg(feature = "async-tls")]
1394 pub async fn establish_tls_async<A: tokio::net::ToSocketAddrs>(
1395 self,
1396 address: A,
1397 ) -> Result<AsyncClientAssociation<AsyncTlsStream>> {
1398 match (&self.tls_config, &self.server_name) {
1399 (Some(tls_config), Some(server_name)) => {
1400 let addr = AeAddr::new_socket_addr(address);
1401 let socket = async_tls_connection(
1402 &addr,
1403 server_name,
1404 &self.socket_options,
1405 tls_config.clone(),
1406 )
1407 .await?;
1408 self.establish_impl_async(addr, socket).await
1409 }
1410 _ => crate::association::TlsConfigMissingSnafu.fail()?,
1411 }
1412 }
1413
1414 #[allow(unreachable_patterns)]
1440 pub async fn establish_with_async(
1441 self,
1442 ae_address: &str,
1443 ) -> Result<AsyncClientAssociation<tokio::net::TcpStream>> {
1444 match ae_address.try_into() {
1445 Ok(ae_address) => {
1446 let socket = async_connection(&ae_address, &self.socket_options).await?;
1447 self.establish_impl_async(ae_address, socket).await
1448 }
1449 Err(_) => {
1450 let addr = AeAddr::new_socket_addr(ae_address);
1451 let socket = async_connection(&addr, &self.socket_options).await?;
1452 self.establish_impl_async(addr, socket).await
1453 }
1454 }
1455 }
1456
1457 #[cfg(feature = "async-tls")]
1483 #[allow(unreachable_patterns)]
1484 pub async fn establish_with_async_tls(
1485 self,
1486 ae_address: &str,
1487 ) -> Result<AsyncClientAssociation<AsyncTlsStream>> {
1488 match (&self.tls_config, &self.server_name) {
1489 (Some(tls_config), Some(server_name)) => match ae_address.try_into() {
1490 Ok(ae_address) => {
1491 let socket = async_tls_connection(
1492 &ae_address,
1493 server_name,
1494 &self.socket_options,
1495 tls_config.clone(),
1496 )
1497 .await?;
1498 self.establish_impl_async(ae_address, socket).await
1499 }
1500 Err(_) => {
1501 let addr = AeAddr::new_socket_addr(ae_address);
1502 let socket = async_tls_connection(
1503 &addr,
1504 server_name,
1505 &self.socket_options,
1506 tls_config.clone(),
1507 )
1508 .await?;
1509 self.establish_impl_async(addr, socket).await
1510 }
1511 },
1512 _ => crate::association::TlsConfigMissingSnafu.fail()?,
1513 }
1514 }
1515}
1516
1517#[cfg(feature = "async")]
1518impl<S> Association for AsyncClientAssociation<S> {
1519 fn peer_ae_title(&self) -> &str {
1520 &self.peer_ae_title
1521 }
1522
1523 fn acceptor_max_pdu_length(&self) -> u32 {
1526 self.acceptor_max_pdu_length
1527 }
1528
1529 fn requestor_max_pdu_length(&self) -> u32 {
1532 self.requestor_max_pdu_length
1533 }
1534
1535 fn local_max_pdu_length(&self) -> u32 {
1538 self.requestor_max_pdu_length
1539 }
1540
1541 fn peer_max_pdu_length(&self) -> u32 {
1544 self.acceptor_max_pdu_length
1545 }
1546
1547 fn presentation_contexts(&self) -> &[PresentationContextNegotiated] {
1548 &self.presentation_contexts
1549 }
1550
1551 fn user_variables(&self) -> &[UserVariableItem] {
1552 &self.user_variables
1553 }
1554}
1555
1556#[cfg(feature = "async")]
1557impl<S> AsyncClientAssociation<S> {
1558 pub fn read_timeout(&self) -> Option<Duration> {
1560 self.read_timeout
1561 }
1562
1563 pub fn write_timeout(&self) -> Option<Duration> {
1565 self.write_timeout
1566 }
1567
1568 pub fn acceptor_max_pdu_length(&self) -> u32 {
1571 self.acceptor_max_pdu_length
1572 }
1573
1574 pub fn requestor_max_pdu_length(&self) -> u32 {
1577 self.requestor_max_pdu_length
1578 }
1579
1580 pub fn user_variables(&self) -> &[UserVariableItem] {
1585 &self.user_variables
1586 }
1587
1588 pub fn presentation_contexts(&self) -> &[PresentationContextNegotiated] {
1590 &self.presentation_contexts
1591 }
1592}
1593
1594#[cfg(feature = "async")]
1596impl<S> AsyncClientAssociation<S>
1597where
1598 S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send,
1599{
1600 pub fn inner_stream(&mut self) -> &mut S {
1610 AsyncAssociation::inner_stream(self)
1611 }
1612
1613 pub async fn send(&mut self, msg: &Pdu) -> Result<()> {
1615 AsyncAssociation::send(self, msg).await
1616 }
1617
1618 pub async fn receive(&mut self) -> Result<Pdu> {
1620 AsyncAssociation::receive(self).await
1621 }
1622
1623 pub async fn release(self) -> Result<()> {
1633 AsyncAssociation::release(self).await
1634 }
1635
1636 pub async fn abort(self) -> Result<()> {
1640 AsyncAssociation::abort(self).await
1641 }
1642
1643 pub fn send_pdata(
1649 &mut self,
1650 presentation_context_id: u8,
1651 ) -> crate::association::pdata::non_blocking::AsyncPDataWriter<&mut S> {
1652 AsyncAssociation::send_pdata(self, presentation_context_id)
1653 }
1654
1655 pub fn receive_pdata(&mut self) -> crate::association::pdata::PDataReader<'_, &mut S> {
1661 AsyncAssociation::receive_pdata(self)
1662 }
1663}
1664
1665#[cfg(feature = "async")]
1666impl<S> super::private::AsyncAssociationSealed<S> for AsyncClientAssociation<S>
1667where
1668 S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send,
1669{
1670 async fn send(&mut self, msg: &Pdu) -> Result<()> {
1671 use tokio::io::AsyncWriteExt;
1672
1673 self.write_buffer.clear();
1674 encode_pdu(
1675 &mut self.write_buffer,
1676 msg,
1677 self.acceptor_max_pdu_length + PDU_HEADER_SIZE,
1678 )?;
1679 super::timeout(self.write_timeout, async {
1680 self.socket
1681 .write_all(&self.write_buffer)
1682 .await
1683 .context(crate::association::WireSendSnafu)
1684 })
1685 .await
1686 }
1687
1688 async fn receive(&mut self) -> Result<Pdu> {
1689 use crate::association::read_pdu_from_wire_async;
1690 super::timeout(self.read_timeout, async {
1691 read_pdu_from_wire_async(
1692 &mut self.socket,
1693 &mut self.read_buffer,
1694 self.requestor_max_pdu_length,
1695 self.strict,
1696 )
1697 .await
1698 })
1699 .await
1700 }
1701
1702 async fn close(&mut self) -> std::io::Result<()> {
1703 use tokio::io::AsyncWriteExt;
1704 self.socket.shutdown().await
1705 }
1706}
1707
1708#[cfg(feature = "async")]
1709impl<S> AsyncAssociation<S> for AsyncClientAssociation<S>
1710where
1711 S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send,
1712{
1713 fn inner_stream(&mut self) -> &mut S {
1714 &mut self.socket
1715 }
1716
1717 fn get_mut(&mut self) -> (&mut S, &mut BytesMut) {
1718 let Self {
1719 socket,
1720 read_buffer,
1721 ..
1722 } = self;
1723 (socket, read_buffer)
1724 }
1725}
1726
1727#[cfg(test)]
1728mod tests {
1729 use super::*;
1730 #[cfg(feature = "async")]
1731 use crate::association::read_pdu_from_wire_async;
1732 use std::io::Write;
1733
1734 impl<'a> ClientAssociationOptions<'a> {
1735 pub(crate) fn establish_with_extra_pdus<T>(
1736 &self,
1737 ae_address: AeAddr<T>,
1738 extra_pdus: Vec<Pdu>,
1739 ) -> Result<ClientAssociation<std::net::TcpStream>>
1740 where
1741 T: ToSocketAddrs,
1742 {
1743 let (pc_proposed, a_associate) = self.create_a_associate_req(ae_address.ae_title())?;
1744 let mut socket = tcp_connection(&ae_address, &self.socket_options)?;
1745 let mut write_buffer: Vec<u8> = Vec::with_capacity(DEFAULT_MAX_PDU as usize);
1746 write_pdu(&mut write_buffer, &a_associate).context(crate::association::SendPduSnafu)?;
1749 for pdu in extra_pdus {
1750 write_pdu(&mut write_buffer, &pdu).context(crate::association::SendPduSnafu)?;
1751 }
1752 socket
1753 .write_all(&write_buffer)
1754 .context(crate::association::WireSendSnafu)?;
1755 write_buffer.clear();
1756
1757 let mut read_buffer = BytesMut::with_capacity(
1758 (self.max_pdu_length.min(LARGE_PDU_SIZE) + PDU_HEADER_SIZE) as usize,
1759 );
1760 let resp = read_pdu_from_wire(
1761 &mut socket,
1762 &mut read_buffer,
1763 self.max_pdu_length,
1764 self.strict,
1765 )?;
1766 let NegotiatedOptions {
1767 presentation_contexts,
1768 peer_max_pdu_length,
1769 user_variables,
1770 peer_ae_title,
1771 } = self
1772 .process_a_association_resp(resp, &pc_proposed)
1773 .expect("Failed to process a associate response");
1774 Ok(ClientAssociation {
1775 presentation_contexts,
1776 requestor_max_pdu_length: self.max_pdu_length,
1777 acceptor_max_pdu_length: peer_max_pdu_length,
1778 socket,
1779 write_buffer,
1780 strict: self.strict,
1781 read_buffer,
1783 read_timeout: self.socket_options.read_timeout,
1784 write_timeout: self.socket_options.write_timeout,
1785 user_variables,
1786 peer_ae_title,
1787 })
1788 }
1789
1790 #[cfg(feature = "async")]
1791 pub(crate) async fn establish_with_extra_pdus_async<T>(
1792 &self,
1793 ae_address: AeAddr<T>,
1794 extra_pdus: Vec<Pdu>,
1795 ) -> Result<AsyncClientAssociation<tokio::net::TcpStream>>
1796 where
1797 T: tokio::net::ToSocketAddrs,
1798 {
1799 use tokio::io::AsyncWriteExt;
1800
1801 let (pc_proposed, a_associate) = self.create_a_associate_req(ae_address.ae_title())?;
1802 let mut socket = async_connection(&ae_address, &self.socket_options).await?;
1803 let mut buffer: Vec<u8> = Vec::with_capacity(DEFAULT_MAX_PDU as usize);
1804 write_pdu(&mut buffer, &a_associate).context(crate::association::SendPduSnafu)?;
1807 for pdu in extra_pdus {
1808 write_pdu(&mut buffer, &pdu).context(crate::association::SendPduSnafu)?;
1809 }
1810 socket
1811 .write_all(&buffer)
1812 .await
1813 .context(crate::association::WireSendSnafu)?;
1814 buffer.clear();
1815
1816 let mut buf = BytesMut::with_capacity(
1817 (self.max_pdu_length.min(LARGE_PDU_SIZE) + PDU_HEADER_SIZE) as usize,
1818 );
1819 let resp =
1820 read_pdu_from_wire_async(&mut socket, &mut buf, self.max_pdu_length, self.strict)
1821 .await?;
1822 let NegotiatedOptions {
1823 presentation_contexts,
1824 peer_max_pdu_length,
1825 user_variables,
1826 peer_ae_title,
1827 } = self
1828 .process_a_association_resp(resp, &pc_proposed)
1829 .expect("Failed to process a associate response");
1830 Ok(AsyncClientAssociation {
1831 presentation_contexts,
1832 requestor_max_pdu_length: self.max_pdu_length,
1833 acceptor_max_pdu_length: peer_max_pdu_length,
1834 socket,
1835 write_buffer: buffer,
1836 strict: self.strict,
1837 read_buffer: buf,
1839 read_timeout: self.socket_options.read_timeout,
1840 write_timeout: self.socket_options.write_timeout,
1841 user_variables,
1842 peer_ae_title,
1843 })
1844 }
1845
1846 pub fn broken_establish<T>(
1848 &self,
1849 ae_address: AeAddr<T>,
1850 ) -> Result<ClientAssociation<std::net::TcpStream>>
1851 where
1852 T: ToSocketAddrs,
1853 {
1854 let (pc_proposed, a_associate) = self.create_a_associate_req(ae_address.ae_title())?;
1855 let mut socket = tcp_connection(&ae_address, &self.socket_options)?;
1856 let mut buffer: Vec<u8> = Vec::with_capacity(DEFAULT_MAX_PDU as usize);
1857 write_pdu(&mut buffer, &a_associate).context(crate::association::SendPduSnafu)?;
1859 socket
1860 .write_all(&buffer)
1861 .context(crate::association::WireSendSnafu)?;
1862 buffer.clear();
1863
1864 let mut buf = BytesMut::with_capacity(
1865 (self.max_pdu_length.min(LARGE_PDU_SIZE) + PDU_HEADER_SIZE) as usize,
1866 );
1867 let resp = read_pdu_from_wire(&mut socket, &mut buf, self.max_pdu_length, self.strict)?;
1868 let NegotiatedOptions {
1869 presentation_contexts,
1870 peer_max_pdu_length,
1871 user_variables,
1872 peer_ae_title,
1873 } = self
1874 .process_a_association_resp(resp, &pc_proposed)
1875 .expect("Failed to process a associate response");
1876 Ok(ClientAssociation {
1877 presentation_contexts,
1878 requestor_max_pdu_length: self.max_pdu_length,
1879 acceptor_max_pdu_length: peer_max_pdu_length,
1880 socket,
1881 write_buffer: buffer,
1882 strict: self.strict,
1883 read_buffer: BytesMut::with_capacity(
1884 (self.max_pdu_length.min(LARGE_PDU_SIZE) + PDU_HEADER_SIZE) as usize,
1885 ),
1886 read_timeout: self.socket_options.read_timeout,
1887 write_timeout: self.socket_options.write_timeout,
1888 user_variables,
1889 peer_ae_title,
1890 })
1891 }
1892
1893 #[cfg(feature = "async")]
1894 pub async fn broken_establish_async<T>(
1896 &self,
1897 ae_address: AeAddr<T>,
1898 ) -> Result<AsyncClientAssociation<tokio::net::TcpStream>>
1899 where
1900 T: tokio::net::ToSocketAddrs,
1901 {
1902 use tokio::io::AsyncWriteExt;
1903
1904 let (pc_proposed, a_associate) = self.create_a_associate_req(ae_address.ae_title())?;
1905 let mut socket = async_connection(&ae_address, &self.socket_options).await?;
1906 let mut buffer: Vec<u8> = Vec::with_capacity(DEFAULT_MAX_PDU as usize);
1907 write_pdu(&mut buffer, &a_associate).context(crate::association::SendPduSnafu)?;
1909 socket
1910 .write_all(&buffer)
1911 .await
1912 .context(crate::association::WireSendSnafu)?;
1913 buffer.clear();
1914
1915 let mut buf = BytesMut::with_capacity(
1916 (self.max_pdu_length.min(LARGE_PDU_SIZE) + PDU_HEADER_SIZE) as usize,
1917 );
1918 let resp =
1919 read_pdu_from_wire_async(&mut socket, &mut buf, self.max_pdu_length, self.strict)
1920 .await?;
1921 let NegotiatedOptions {
1922 presentation_contexts,
1923 peer_max_pdu_length,
1924 user_variables,
1925 peer_ae_title,
1926 } = self
1927 .process_a_association_resp(resp, &pc_proposed)
1928 .expect("Failed to process a associate response");
1929 Ok(AsyncClientAssociation {
1930 presentation_contexts,
1931 requestor_max_pdu_length: self.max_pdu_length,
1932 acceptor_max_pdu_length: peer_max_pdu_length,
1933 socket,
1934 write_buffer: buffer,
1935 strict: self.strict,
1936 read_buffer: BytesMut::with_capacity(
1937 (self.max_pdu_length.min(LARGE_PDU_SIZE) + PDU_HEADER_SIZE) as usize,
1938 ),
1939 read_timeout: self.socket_options.read_timeout,
1940 write_timeout: self.socket_options.write_timeout,
1941 user_variables,
1942 peer_ae_title,
1943 })
1944 }
1945 }
1946}