Enet4 / dicom-rs

Rust implementation of the DICOM standard
https://dicom-rs.github.io
Apache License 2.0
403 stars 75 forks source link

ERROR dicom_findscu: status code from response is missing #479

Closed jennydaman closed 3 months ago

jennydaman commented 3 months ago

I seem to be unable to run dicom-findscu with Orthanc.

I set up Orthanc like this:

https://github.com/FNNDSC/oxidicom/blob/ad8582e90c1ef793871d3618048f0d6fe57fe1b0/docker-compose.yml#L5-L9

With this data:

https://github.com/datalad/example-dicom-structural

Using dcmtk works:

findscu -xi -S -k AccessionNumber -k AcquisitionProtocolDescription -k AcquisitionProtocolName -k InstanceNumber -k ModalitiesInStudy -k Modality -k NumberOfPatientRelatedInstances -k NumberOfPatientRelatedSeries -k NumberOfPatientRelatedStudies -k NumberOfSeriesRelatedInstances -k NumberOfStudyRelatedInstances -k NumberOfStudyRelatedSeries -k PatientAge -k PatientBirthDate -k PatientID -k PatientName=Jane_Doe -k PatientSex -k PerformedStationAETitle -k ProtocolName -k QueryRetrieveLevel=STUDY -k SeriesDate -k SeriesDescription -k SeriesInstanceUID -k StudyDate -k StudyDescription -k StudyInstanceUID -aec OXIORTHANCTEST -aet OXIDICOMTEST localhost 4242 

But dicom-findscu of dicom-rs causes an error:

$ cargo run --bin dicom-findscu -- localhost:4242 --calling-ae-title=OXIDICOMTEST --called-ae-title=OXIORTHANCTEST --study -q PatientName='Jane_Doe'

------------------------ Match #0 ------------------------
(0008,0005) SpecificCharacterSet         CS (1, 10 bytes): "ISO_IR 100"
(0008,0052) QueryRetrieveLevel           CS (1,  6 bytes): "STUDY"
(0008,0054) RetrieveAETitle              AE (1, 14 bytes): "OXITESTORTHANC"
(0010,0010) PatientName                  PN (1,  8 bytes): "Jane_Doe"
2024-03-19T04:12:57.046352Z ERROR dicom_findscu: status code from response is missing
Enet4 commented 3 months ago

Thank you for reporting. Would you be able to include some verbose output of that call to Dcmtk's findscu?

In any case, this might be a regression from the changes done in #434.

jennydaman commented 3 months ago
D: $dcmtk: findscu v3.6.8 2023-12-19 $
D:
D: DcmDataDictionary: Loading file: /usr/share/dcmtk-3.6.8/dicom.dic
D: Request Parameters:
D: ====================== BEGIN A-ASSOCIATE-RQ =====================
D: Our Implementation Class UID:      1.2.276.0.7230010.3.0.3.6.8
D: Our Implementation Version Name:   OFFIS_DCMTK_368
D: Their Implementation Class UID:
D: Their Implementation Version Name:
D: Application Context Name:    1.2.840.10008.3.1.1.1
D: Calling Application Name:    OXIDICOMTEST
D: Called Application Name:     OXIORTHANCTEST
D: Responding Application Name:
D: Our Max PDU Receive Size:    16384
D: Their Max PDU Receive Size:  0
D: Presentation Contexts:
D:   Context ID:        1 (Proposed)
D:     Abstract Syntax: =FINDStudyRootQueryRetrieveInformationModel
D:     Proposed SCP/SCU Role: Default
D:     Proposed Transfer Syntax(es):
D:       =LittleEndianImplicit
D: Requested Extended Negotiation: none
D: Accepted Extended Negotiation:  none
D: Requested User Identity Negotiation: none
D: User Identity Negotiation Response:  none
D: ======================= END A-ASSOCIATE-RQ ======================
I: Requesting Association
D: setting network send timeout to 60 seconds
D: setting network receive timeout to 60 seconds
D: Constructing Associate RQ PDU
D: PDU Type: Associate Accept, PDU Length: 184 + 6 bytes PDU header
D:   02  00  00  00  00  b8  00  01  00  00  4f  58  49  4f  52  54
D:   48  41  4e  43  54  45  53  54  20  20  4f  58  49  44  49  43
D:   4f  4d  54  45  53  54  20  20  20  20  00  00  00  00  00  00
D:   00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
D:   00  00  00  00  00  00  00  00  00  00  10  00  00  15  31  2e
D:   32  2e  38  34  30  2e  31  30  30  30  38  2e  33  2e  31  2e
D:   31  2e  31  21  00  00  19  01  00  00  00  40  00  00  11  31
D:   2e  32  2e  38  34  30  2e  31  30  30  30  38  2e  31  2e  32
D:   50  00  00  3a  51  00  00  04  00  00  40  00  52  00  00  1b
D:   31  2e  32  2e  32  37  36  2e  30  2e  37  32  33  30  30  31
D:   30  2e  33  2e  30  2e  33  2e  36  2e  38  55  00  00  0f  4f
D:   46  46  49  53  5f  44  43  4d  54  4b  5f  33  36  38
D: Parsing an A-ASSOCIATE PDU
D: Association Parameters Negotiated:
D: ====================== BEGIN A-ASSOCIATE-AC =====================
D: Our Implementation Class UID:      1.2.276.0.7230010.3.0.3.6.8
D: Our Implementation Version Name:   OFFIS_DCMTK_368
D: Their Implementation Class UID:    1.2.276.0.7230010.3.0.3.6.8
D: Their Implementation Version Name: OFFIS_DCMTK_368
D: Application Context Name:    1.2.840.10008.3.1.1.1
D: Calling Application Name:    OXIDICOMTEST
D: Called Application Name:     OXIORTHANCTEST
D: Responding Application Name: OXIORTHANCTEST
D: Our Max PDU Receive Size:    16384
D: Their Max PDU Receive Size:  16384
D: Presentation Contexts:
D:   Context ID:        1 (Accepted)
D:     Abstract Syntax: =FINDStudyRootQueryRetrieveInformationModel
D:     Proposed SCP/SCU Role: Default
D:     Accepted SCP/SCU Role: Default
D:     Accepted Transfer Syntax: =LittleEndianImplicit
D: Requested Extended Negotiation: none
D: Accepted Extended Negotiation:  none
D: Requested User Identity Negotiation: none
D: User Identity Negotiation Response:  none
D: ======================= END A-ASSOCIATE-AC ======================
I: Association Accepted (Max Send PDV: 16372)
I: Sending Find Request
D: ===================== OUTGOING DIMSE MESSAGE ====================
D: Message Type                  : C-FIND RQ
D: Presentation Context ID       : 1
D: Message ID                    : 1
D: Affected SOP Class UID        : FINDStudyRootQueryRetrieveInformationModel
D: Data Set                      : present
D: Priority                      : medium
D: ======================= END DIMSE MESSAGE =======================
I: Request Identifiers:
I:
I: # Dicom-Data-Set
I: # Used TransferSyntax: Little Endian Explicit
I: (0008,0020) DA (no value available)                     #   0, 0 StudyDate
I: (0008,0021) DA (no value available)                     #   0, 0 SeriesDate
I: (0008,0050) SH (no value available)                     #   0, 0 AccessionNumber
I: (0008,0052) CS [STUDY]                                  #   6, 1 QueryRetrieveLevel
I: (0008,0060) CS (no value available)                     #   0, 0 Modality
I: (0008,0061) CS (no value available)                     #   0, 0 ModalitiesInStudy
I: (0008,1030) LO (no value available)                     #   0, 0 StudyDescription
I: (0008,103e) LO (no value available)                     #   0, 0 SeriesDescription
I: (0010,0010) PN [Jane_Doe]                               #   8, 1 PatientName
I: (0010,0020) LO (no value available)                     #   0, 0 PatientID
I: (0010,0030) DA (no value available)                     #   0, 0 PatientBirthDate
I: (0010,0040) CS (no value available)                     #   0, 0 PatientSex
I: (0010,1010) AS (no value available)                     #   0, 0 PatientAge
I: (0018,1030) LO (no value available)                     #   0, 0 ProtocolName
I: (0018,9423) LO (no value available)                     #   0, 0 AcquisitionProtocolName
I: (0018,9424) LT (no value available)                     #   0, 0 AcquisitionProtocolDescription
I: (0020,000d) UI (no value available)                     #   0, 0 StudyInstanceUID
I: (0020,000e) UI (no value available)                     #   0, 0 SeriesInstanceUID
I: (0020,0013) IS (no value available)                     #   0, 0 InstanceNumber
I: (0020,1200) IS (no value available)                     #   0, 0 NumberOfPatientRelatedStudies
I: (0020,1202) IS (no value available)                     #   0, 0 NumberOfPatientRelatedSeries
I: (0020,1204) IS (no value available)                     #   0, 0 NumberOfPatientRelatedInstances
I: (0020,1206) IS (no value available)                     #   0, 0 NumberOfStudyRelatedSeries
I: (0020,1208) IS (no value available)                     #   0, 0 NumberOfStudyRelatedInstances
I: (0020,1209) IS (no value available)                     #   0, 0 NumberOfSeriesRelatedInstances
I: (0040,0241) AE (no value available)                     #   0, 0 PerformedStationAETitle
I:
D: DcmDataset::read() TransferSyntax="Little Endian Implicit"
D: DcmDataset::read() TransferSyntax="Little Endian Implicit"
I: Received Find Response 1
D: ===================== INCOMING DIMSE MESSAGE ====================
D: Message Type                  : C-FIND RSP
D: Message ID Being Responded To : 1
D: Affected SOP Class UID        : FINDStudyRootQueryRetrieveInformationModel
D: Data Set                      : present
D: DIMSE Status                  : 0xff00: Pending: Matches are continuing
D: ======================= END DIMSE MESSAGE =======================
D: Response Identifiers:
D:
D: # Dicom-Data-Set
D: # Used TransferSyntax: Little Endian Implicit
D: (0008,0005) CS [ISO_IR 100]                             #  10, 1 SpecificCharacterSet
D: (0008,0020) DA [20130717]                               #   8, 1 StudyDate
D: (0008,0021) DA [20130717]                               #   8, 1 SeriesDate
D: (0008,0050) SH (no value available)                     #   0, 0 AccessionNumber
D: (0008,0052) CS [STUDY ]                                 #   6, 1 QueryRetrieveLevel
D: (0008,0054) AE [OXITESTORTHANC]                         #  14, 1 RetrieveAETitle
D: (0008,0060) CS [MR]                                     #   2, 1 Modality
D: (0008,0061) CS [MR]                                     #   2, 1 ModalitiesInStudy
D: (0008,1030) LO [Hanke_Stadler^0024_transrep ]           #  28, 1 StudyDescription
D: (0008,103e) LO [anat-T1w]                               #   8, 1 SeriesDescription
D: (0010,0010) PN [Jane_Doe]                               #   8, 1 PatientName
D: (0010,0020) LO [02]                                     #   2, 1 PatientID
D: (0010,0030) DA [19660101]                               #   8, 1 PatientBirthDate
D: (0010,0040) CS [F ]                                     #   2, 1 PatientSex
D: (0010,1010) AS [42]                                     #   2, 1 PatientAge
D: (0018,1030) LO [anat-T1w]                               #   8, 1 ProtocolName
D: (0018,9423) LO (no value available)                     #   0, 0 AcquisitionProtocolName
D: (0018,9424) LT (no value available)                     #   0, 0 AcquisitionProtocolDescription
D: (0020,000d) UI [1.2.826.0.1.3680043.2.1143.2592092611698916978113112155415165916] #  64, 1 StudyInstanceUID
D: (0020,000e) UI [1.2.826.0.1.3680043.2.1143.515404396022363061013111326823367652] #  64, 1 SeriesInstanceUID
D: (0020,0013) IS [1 ]                                     #   2, 1 InstanceNumber
D: (0020,1200) IS (no value available)                     #   0, 0 NumberOfPatientRelatedStudies
D: (0020,1202) IS (no value available)                     #   0, 0 NumberOfPatientRelatedSeries
D: (0020,1204) IS (no value available)                     #   0, 0 NumberOfPatientRelatedInstances
D: (0020,1206) IS [1 ]                                     #   2, 1 NumberOfStudyRelatedSeries
D: (0020,1208) IS [384 ]                                   #   4, 1 NumberOfStudyRelatedInstances
D: (0020,1209) IS (no value available)                     #   0, 0 NumberOfSeriesRelatedInstances
D: (0040,0241) AE (no value available)                     #   0, 0 PerformedStationAETitle
D:
D: DcmDataset::read() TransferSyntax="Little Endian Implicit"
I: Received Final Find Response
D: ===================== INCOMING DIMSE MESSAGE ====================
D: Message Type                  : C-FIND RSP
D: Message ID Being Responded To : 1
D: Affected SOP Class UID        : FINDStudyRootQueryRetrieveInformationModel
D: Data Set                      : none
D: DIMSE Status                  : 0x0000: Success: Matching is complete
D: ======================= END DIMSE MESSAGE =======================
I: Releasing Association
jennydaman commented 3 months ago

I took a look at #434 and blindly tried to undo it:

diff --git a/findscu/src/main.rs b/findscu/src/main.rs
index 0b176b5..8168d60 100644
--- a/findscu/src/main.rs
+++ b/findscu/src/main.rs
@@ -281,6 +281,7 @@ fn run() -> Result<(), Error> {
                         .dump_object_to(stderr(), &cmd_obj)
                         .context(DumpOutputSnafu)?;
                 }
+
                 let status = cmd_obj
                     .get(tags::STATUS)
                     .whatever_context("status code from response is missing")?
@@ -324,9 +325,10 @@ fn run() -> Result<(), Error> {
                     // upon sending the response data
                     let status = dcm
                         .get(tags::STATUS)
-                        .whatever_context("status code from response is missing")?
-                        .to_int::<u16>()
-                        .whatever_context("failed to read status code")?;
+                        .map(|ele| ele.to_int::<u16>())
+                        .transpose()
+                        .whatever_context("failed to read status code")?
+                        .unwrap_or(0);

                     if status == 0 {
                         if verbose {

The result of dicom-findscu is now that it exits gracefully, nor do I see errors in Orthanc's logs. However I don't actually know what the protocol is so I am not sure whether this is a well-behaved solution.