Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics

Dashboard
Notifications
Mark all as read
Q&A

Fail to send DICOM C-Echo, although DICOM Association seems successful.

+6
−0

I am building an Android app to perform a DICOM C-Echo. (DICOM is a standard for storing and transferring medical images; the specification is at dicom.nema.org). My purpose is to learn more about how DICOM works, by implementing things myself.

To test my application, I use DCMTk's storescp command, which implements the receiving party of a DICOM C-Echo. So, on my VPS, which runs Ubuntu, I give this command:

sudo storescp -d 104

(The "-d" flag is for "debug", giving me extra information).

When I use DCMTk to create a DICOM Association, I get the following response:

D: $dcmtk: storescp v3.6.2 2017-07-14 $
D:
D: DcmDataDictionary: Loading file: /usr/share/libdcmtk12/dicom.dic
D: DcmDataDictionary: Loading file: /usr/share/libdcmtk12/private.dic
D: setting network send timeout to 60 seconds
D: setting network receive timeout to 60 seconds
D: PDU Type: Associate Request, PDU Length: 205 + 6 bytes PDU header
D:   01  00  00  00  00  cd  00  01  00  00  41  4e  59  2d  53  43
D:   50  20  20  20  20  20  20  20  20  20  45  43  48  4f  53  43
D:   55  20  20  20  20  20  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  20  00  00  2e  01  00  ff  00  30  00  00  11  31
D:   2e  32  2e  38  34  30  2e  31  30  30  30  38  2e  31  2e  31
D:   40  00  00  11  31  2e  32  2e  38  34  30  2e  31  30  30  30
D:   38  2e  31  2e  32  50  00  00  3a  51  00  00  04  00  00  40
D:   00  52  00  00  1b  31  2e  32  2e  32  37  36  2e  30  2e  37
D:   32  33  30  30  31  30  2e  33  2e  30  2e  33  2e  36  2e  32
D:   55  00  00  0f  4f  46  46  49  53  5f  44  43  4d  54  4b  5f
D:   33  36  32
D: Parsing an A-ASSOCIATE PDU
I: Association Received
D: Parameters:
D: ====================== BEGIN A-ASSOCIATE-RQ =====================
D: Our Implementation Class UID:      1.2.276.0.7230010.3.0.3.6.2
D: Our Implementation Version Name:   OFFIS_DCMTK_362
D: Their Implementation Class UID:    1.2.276.0.7230010.3.0.3.6.2
D: Their Implementation Version Name: OFFIS_DCMTK_362
D: Application Context Name:    1.2.840.10008.3.1.1.1
D: Calling Application Name:    ECHOSCU
D: Called Application Name:     ANY-SCP
D: Responding Application Name:
D: Our Max PDU Receive Size:    16384
D: Their Max PDU Receive Size:  16384
D: Presentation Contexts:
D:   Context ID:        1 (Proposed)
D:     Abstract Syntax: =VerificationSOPClass
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 ======================
D: Constructing Associate AC PDU
I: Association Acknowledged (Max Send PDV: 16372)
D: ====================== BEGIN A-ASSOCIATE-AC =====================
D: Our Implementation Class UID:      1.2.276.0.7230010.3.0.3.6.2
D: Our Implementation Version Name:   OFFIS_DCMTK_362
D: Their Implementation Class UID:    1.2.276.0.7230010.3.0.3.6.2
D: Their Implementation Version Name: OFFIS_DCMTK_362
D: Application Context Name:    1.2.840.10008.3.1.1.1
D: Calling Application Name:    ECHOSCU
D: Called Application Name:     ANY-SCP
D: Responding Application Name: ANY-SCP
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: =VerificationSOPClass
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 ======================
D: DcmDataset::read() TransferSyntax="Little Endian Implicit"
I: Received Echo Request
D: ===================== INCOMING DIMSE MESSAGE ====================
D: Message Type                  : C-ECHO RQ
D: Presentation Context ID       : 1
D: Message ID                    : 1
D: Data Set                      : none
D: ======================= END DIMSE MESSAGE =======================
I: Association Release

When I use my app to establish the DICOM Association, I get a similar result:

D: setting network send timeout to 60 seconds
D: setting network receive timeout to 60 seconds
D: PDU Type: Associate Request, PDU Length: 188 + 6 bytes PDU header
D:   01  00  00  00  00  bc  00  01  00  00  41  4e  59  2d  53  43
D:   50  20  20  20  20  20  20  20  20  20  45  43  48  4f  53  43
D:   55  20  20  20  20  20  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  20  00  00  2e  01  00  00  00  30  00  00  11  31
D:   2e  32  2e  38  34  30  2e  31  30  30  30  38  2e  31  2e  31
D:   40  00  00  11  31  2e  32  2e  38  34  30  2e  31  30  30  30
D:   38  2e  31  2e  32  50  00  00  29  51  00  00  04  00  00  40
D:   00  52  00  00  15  31  2e  32  2e  38  34  30  2e  31  30  30
D:   30  38  2e  33  2e  31  2e  31  2e  31  53  00  00  04  00  01
D:   00  01
D: Parsing an A-ASSOCIATE PDU
I: Association Received
D: Parameters:
D: ====================== BEGIN A-ASSOCIATE-RQ =====================
D: Our Implementation Class UID:      1.2.276.0.7230010.3.0.3.6.2
D: Our Implementation Version Name:   OFFIS_DCMTK_362
D: Their Implementation Class UID:    1.2.840.10008.3.1.1.1
D: Their Implementation Version Name:
D: Application Context Name:    1.2.840.10008.3.1.1.1
D: Calling Application Name:    ECHOSCU
D: Called Application Name:     ANY-SCP
D: Responding Application Name:
D: Our Max PDU Receive Size:    16384
D: Their Max PDU Receive Size:  16384
D: Presentation Contexts:
D:   Context ID:        1 (Proposed)
D:     Abstract Syntax: =VerificationSOPClass
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 ======================
D: Constructing Associate AC PDU
I: Association Acknowledged (Max Send PDV: 16372)
D: ====================== BEGIN A-ASSOCIATE-AC =====================
D: Our Implementation Class UID:      1.2.276.0.7230010.3.0.3.6.2
D: Our Implementation Version Name:   OFFIS_DCMTK_362
D: Their Implementation Class UID:    1.2.840.10008.3.1.1.1
D: Their Implementation Version Name:
D: Application Context Name:    1.2.840.10008.3.1.1.1
D: Calling Application Name:    ECHOSCU
D: Called Application Name:     ANY-SCP
D: Responding Application Name: ANY-SCP
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: =VerificationSOPClass
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 ======================
E: DIMSE failure (aborting association): 0006:020d DIMSE Failed to receive message
E: 0006:020c DIMSE Read PDV failed
E: 0006:0321 Unrecognized PDU type:  0

So, in both cases, the response is A-ASSOCIATE-AC, meaning the DICOM Association is accepted. (The other possible responses are A-ASSOCIATE-RJ, when it is rejected, and A-ABORT, when it fails disastrously).

When I use DCMTk's echoscu to send an Echo request, things work smooth:

D: DcmDataset::read() TransferSyntax="Little Endian Implicit"
I: Received Echo Request
D: ===================== INCOMING DIMSE MESSAGE ====================
D: Message Type                  : C-ECHO RQ
D: Presentation Context ID       : 1
D: Message ID                    : 1
D: Data Set                      : none
D: ======================= END DIMSE MESSAGE =======================

However, when I use my app to send the request message, I get this:

E: DIMSE failure (aborting association): 0006:020d DIMSE Failed to receive message
E: 0006:020c DIMSE Read PDV failed
E: 0006:0321 Unrecognized PDU type:  0

I have inspected DCMTk's echoscu message using Wireshark. and it sends almost the same bytes that I send.

These are the bytes that DCMTK's echoscu sends, broken down into DICOM Elements.

00 00        g = 0000
00 00        e = 0000
04 00 00 00  VR length = 4
38 00 00 00  VR value = 0x38 = 56 dec

00 00        g=0000
02 00        e=0000
12 00 00 00  VR length = 0x12 = 18dec
31 2e 32 2e 38 34 30 2e 31 30 30 30 38 2e 31 2e 31 00 VR value = 1.2.840.10008.1.1

00 00        g=0000
00 01        e=0100
02 00 00 00  VR length = 2
30 00        VR value = 0030

00 00        g=0000
10 01        e=0110
02 00 00 00  vR length = 2
01 00        VR value = 0001

00 00        g=0000
00 08        e=0800
02 00 00 00  VR length = 2
01 01        VR Value = 0101

These are the bytes that my app sends, again broken down into DICOM elements:

00 00        g=0000
00 00        e=0000
04 00 00 00  VR length = 4  
38 00 00 00  VR value = 56 dec

00 00        g=0000
02 00        e=0002
12 00 00 00  VR length = 18
31 2e 32 2e 38 34 30 2e 31 30 30 30 38 2e 31 2e 31 00 VR value =  1.2.840.10008.1.1
                                                    
00 00        g=0000
00 01        e=0100 
02 00 00 00  VR length = 2
30 00        VR value = 0

00 00        g=0000
10 01        e=0110 
02 00 00 00  VR length = 2
01 00        VR value = 0x0001

00 00        g=0000
00 08        e=0800
02 00 00 00  VR length = 2 
01 01        VR value = 0101

So, it seems a DICOM Association was created succesfully in both cases, and in both cases a very similar series of bytes is sent. So why does the first case succeed, whereas the second case fails?

The error message suggests that I should have sent more: "Unrecognized PDU type: 0". It sounds as if I need to embed my DICOM C-Echo request in something else. Or as if storescp expects me to create a new command at the level of creating and releasing associations, rather than just a DICOM C-Echo request. In fact, when I don't send the bytes for a DICOM C-Echo but just the 10 bytes to release the Assocation (DICOM A-Release-RQ), the association is released smoothly.

So.. what am I missing?

  • Is there an error in the way I set up the DICOM Association?
  • Do I need to embed my DICOM C-Echo Request inside something else?
  • Do I need to set the receiving party (storescp) in a different mode to receive C-Echo, rather than to expect A-Associate-RQ or A-Release-RQ?

Code of the app is on my Github.

EDIT: Since I don't have Wireshark on Android, I decided to run my app from the Android emulator. As @ghost-in-the-zsh suggested, I have made sure that the bytes sent by my app are exactly the same as those sent by DCMTk's echoscu program.

If I do this, I see that Wireshark does not recognize my C-Echo bytes as DICOM. It labels them as TCP. But it does label echoscu's C-Echo bytes as DICOM.
So I'm probably just making a mistake in my networking code.

I have added screenshots of my captures, with the relevant message selected. I can add the captures themselves, if necessary.

Capture of the traffic from the Android emulator to the VPS:

WireShark capture of traffic from Android emulator to VPS

Capture of the traffic from DCMTK's echoscu to the VPS:

WireShark capture of traffic from DCMTK echoscu to VPS

Why does this post require moderator attention?
You might want to add some details to your flag.
Why should this post be closed?

11 comments

I'm not familiar with DICOM, but I have a few questions: Your app is not sending the exact same bytes as the successful request (e.g. VR value = 0001 that works vs your app's VR value = 0xfeca). What's the significance of the different bytes? Why are they even different if you're (apparently) trying to do the same thing? Are you able to check logs for the receiving end of your request? If so, what do you find in them? Warnings? Errors? Something else? If not, then who can check? ghost-in-the-zsh‭ about 1 month ago

@FractionalRadix For future reference, you can create the tag yourself if it doesn't already exist :) Just add it to the tag field when you submit your question and it'll be automatically created Moshi‭ about 1 month ago

@ghost-in-the-zsh Well spotted! The 0xfeca value is arbitrary; it is a value that the receiver must return, so the sender knows it got the right message. (And yes, that's not watertight... but that's the spec). There are no logs from the receiver; using the "-d" option is the most informative you can get. This is because C-ECHO is a very basic operation. The difficult part was in establishing a "DICOM Association" between the two parties. Although now I suspect the issue is in my network code. FractionalRadix‭ about 1 month ago

@Moshi ...so, I unlocked that Ability? That would be nice! I tried adding new tags myself, but it didn't work. FractionalRadix‭ about 1 month ago

@FractionalRadix That's odd, tag creation isn't currently ability-locked. Perhaps raise a bug report? Moshi‭ about 1 month ago

Show 6 more comments

0 answers

Sign up to answer this question »