Skip to content

Commit 17c3718

Browse files
authored
Merge pull request #723 from Enet4/bug/721-establish_with
Fix misinterpretation of AE address as plain socket address in some cases
2 parents 555bfff + 2c68a81 commit 17c3718

File tree

2 files changed

+52
-9
lines changed

2 files changed

+52
-9
lines changed

storescu/src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ fn run(app: App) -> Result<(), Error> {
398398
store_sync::inner(scu, dicom_files, &progress_bar, fail_first, verbose, never_transcode, ignore_sop_class)?;
399399

400400
} else {
401-
let scu = scu_options.establish(&addr).map_err(Box::from).context(ScuSnafu)?;
401+
let scu = scu_options.establish_with(&addr).map_err(Box::from).context(ScuSnafu)?;
402402
store_sync::inner(scu, dicom_files, &progress_bar, fail_first, verbose, never_transcode, ignore_sop_class)?;
403403
}
404404
Ok(())
@@ -505,7 +505,7 @@ async fn run_async() -> Result<(), Error> {
505505
.await
506506
} else {
507507
let scu = scu_options
508-
.establish_async(&addr)
508+
.establish_with_async(&addr)
509509
.await
510510
.map_err(Box::from)
511511
.context(ScuSnafu)?;

ul/tests/association.rs

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
use dicom_dictionary_std::uids::VERIFICATION;
2-
use dicom_ul::ClientAssociationOptions;
1+
use dicom_dictionary_std::uids::{self, VERIFICATION};
2+
use dicom_ul::{ClientAssociationOptions, Pdu, ServerAssociationOptions, association::SyncAssociation};
33
use rstest::rstest;
44
use std::time::Instant;
55
#[cfg(feature = "sync-tls")]
66
use dicom_ul::association::Association;
77
#[cfg(feature = "sync-tls")]
88
use std::sync::Arc;
99

10+
type Result<T, E = Box<dyn std::error::Error + Send + Sync + 'static>> = std::result::Result<T, E>;
11+
1012
#[cfg(feature = "sync-tls")]
11-
fn ensure_test_certs() -> Result<(), Box<dyn std::error::Error>> {
13+
fn ensure_test_certs() -> Result<()> {
1214
use rustls_cert_gen::CertificateBuilder;
1315
use rcgen::SanType;
1416
use std::{convert::TryInto, net::IpAddr, str::FromStr, path::PathBuf};
@@ -68,7 +70,7 @@ const TIMEOUT_TOLERANCE: u64 = 25;
6870

6971
#[cfg(feature = "sync-tls")]
7072
/// Create a test TLS server configuration
71-
fn create_test_config() -> Result<(Arc<rustls::ServerConfig>, Arc<rustls::ClientConfig>), Box<dyn std::error::Error>> {
73+
fn create_test_config() -> Result<(Arc<rustls::ServerConfig>, Arc<rustls::ClientConfig>)> {
7274
use rustls::{ClientConfig, RootCertStore, ServerConfig, pki_types::{CertificateDer, PrivateKeyDer, pem::PemObject}, server::WebPkiClientVerifier};
7375
use std::path::PathBuf;
7476
ensure_test_certs()?;
@@ -188,7 +190,7 @@ fn test_tls_connection_sync() {
188190

189191
#[cfg(feature = "async-tls")]
190192
#[tokio::test(flavor = "multi_thread")]
191-
async fn test_tls_connection_async() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
193+
async fn test_tls_connection_async() -> Result<()> {
192194
use dicom_ul::{ServerAssociationOptions, association::AsyncAssociation};
193195
// set up crypto provider -- Just use the default provider which is aws_lc_rs
194196
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
@@ -205,7 +207,7 @@ async fn test_tls_connection_async() -> Result<(), Box<dyn std::error::Error + S
205207
.tls_config((*server_tls_config).clone());
206208

207209
// Spawn server task
208-
let server_handle = tokio::spawn(async move {
210+
let server_handle: tokio::task::JoinHandle<Result<_>> = tokio::spawn(async move {
209211
let (stream, _) = listener.accept().await.map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync + 'static>)?;
210212
let mut association = server_options.establish_tls_async(stream).await.map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync + 'static>)?;
211213

@@ -219,7 +221,7 @@ async fn test_tls_connection_async() -> Result<(), Box<dyn std::error::Error + S
219221
association.send(&dicom_ul::Pdu::ReleaseRP).await.map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync + 'static>)?;
220222
}
221223

222-
Ok::<(), Box<dyn std::error::Error + Send + Sync + 'static>>(())
224+
Result::Ok(())
223225
});
224226

225227
// Give server time to start
@@ -297,3 +299,44 @@ async fn test_slow_association_async(#[case] timeout: u64) {
297299
timeout
298300
);
299301
}
302+
303+
/// Associations can be established
304+
/// when identifying remote nodes by their application entity address.
305+
#[test]
306+
fn test_establish_via_ae_address() -> Result<()> {
307+
let listener = std::net::TcpListener::bind("localhost:0")?;
308+
let addr = listener.local_addr()?;
309+
let scp = ServerAssociationOptions::new()
310+
.accept_called_ae_title()
311+
.ae_title("THIS-SCP")
312+
.with_abstract_syntax(VERIFICATION);
313+
314+
// Spawn server thread
315+
let h = std::thread::spawn(move || -> Result<_> {
316+
let (stream, _addr) = listener.accept()?;
317+
let mut association = scp.establish(stream)?;
318+
319+
// handle one release request
320+
let pdu = association.receive()?;
321+
assert_eq!(pdu, Pdu::ReleaseRQ);
322+
association.send(&Pdu::ReleaseRP)?;
323+
324+
Ok(association)
325+
});
326+
327+
// use bound socket address to create AE address
328+
let ae_address = format!("THIS-SCP@{addr}");
329+
330+
// create SCU and establish association
331+
let association = ClientAssociationOptions::new()
332+
.calling_ae_title("THIS-SCU")
333+
.with_presentation_context(uids::VERIFICATION, vec![uids::IMPLICIT_VR_LITTLE_ENDIAN, uids::EXPLICIT_VR_LITTLE_ENDIAN])
334+
.establish_with(&ae_address)?;
335+
336+
// just release and finish
337+
association.release()?;
338+
339+
let _ = h.join();
340+
341+
Ok(())
342+
}

0 commit comments

Comments
 (0)