Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PresentationContext Accept Issues #62

Open
suoc opened this issue Jul 23, 2024 · 10 comments
Open

PresentationContext Accept Issues #62

suoc opened this issue Jul 23, 2024 · 10 comments
Assignees
Labels
question Further information is requested

Comments

@suoc
Copy link

suoc commented Jul 23, 2024

I used wireshark to capture the response results of two dimse tools and got different response content. The response structure of dcmjs-dimse seems to be problematic.
This is request:
request

Response by DCMOBJ:
resp-by-DCMOBJ

Response by dcmjs-dimse:
resp-by-dcmjs-dimse

The response of dcmjs-dimse will cause the negotiation on the client side to fail, and the dcm file will not continue to be sent.

@PantelisGeorgiadis PantelisGeorgiadis self-assigned this Jul 25, 2024
@PantelisGeorgiadis PantelisGeorgiadis added the bug Something isn't working label Jul 25, 2024
@PantelisGeorgiadis
Copy link
Owner

Hello @suoc! Thanks for reporting this. There seems to be an issue with the presentation context IDs, which your SCP accepts. Instead of accepting the provided, by the SCU IDs, the SCP seems to take the last one (0x19) and increase it, for every context. Are you somehow altering the presentation context IDs during the association negotiation?

I modified the dcmjs-dimse basic SCP example to reproduce this, as bellow:

const dcmjsDimse = require('dcmjs-dimse');

const { Scp, Server } = dcmjsDimse;
const { CStoreResponse } = dcmjsDimse.responses;
const { PresentationContextResult, Status } = dcmjsDimse.constants;

class ExampleScp extends Scp {
  constructor(socket, opts) {
    super(socket, opts);
    this.association = undefined;
  }

  associationRequested(association) {
    this.association = association;

    const contexts = association.getPresentationContexts();
    contexts.forEach((c) => {
      const context = association.getPresentationContext(c.id);
      const tsIds = context.getTransferSyntaxUids();
      tsIds.forEach((ts) => {
        context.setResult(PresentationContextResult.Accept, ts);
      });
    });

    this.sendAssociationAccept();
  }

  cStoreRequest(request, callback) {
    const response = CStoreResponse.fromRequest(request);
    response.setStatus(Status.Success);
    callback(response);
  }

  associationReleaseRequested() {
    this.sendAssociationReleaseResponse();
  }
}

const server = new Server(ExampleScp);
server.listen(port, { logCommandDatasets: true });

Then I created a basic SCU, using fo-dicom, to emulate sending multiple datasets, as part of the same association. I actually used the files in the datasets folder:

var client = DicomClientFactory.Create("127.0.0.1", 2104, false, "SCU", "ANY-SCP");
await client.AddRequestAsync(new DicomCStoreRequest("ebe.dcm"));
await client.AddRequestAsync(new DicomCStoreRequest("ele.dcm"));
await client.AddRequestAsync(new DicomCStoreRequest("j2k.dcm"));
await client.AddRequestAsync(new DicomCStoreRequest("pdf.dcm"));
await client.AddRequestAsync(new DicomCStoreRequest("sr.dcm"));
await client.SendAsync();

Bellow are the SCP generated logs:

2024-07-25T08:57:56.873Z -- INFO -- Client connecting from ::ffff:127.0.0.1:56867 
2024-07-25T08:57:56.924Z -- INFO -- SCU <- Association request:
Application Context:     1.2.840.10008.3.1.1.1
Implementation Class:    1.3.6.1.4.1.30071.8
Implementation Version:  fo-dicom 5.1.2
Maximum PDU Length:      262144
Called AE Title:         ANY-SCP
Calling AE Title:        SCU
Presentation Contexts:   8
  Presentation Context:  1 [Proposed]
      Abstract:  MrImageStorage
      Transfer:  ExplicitVRBigEndian
  Presentation Context:  3 [Proposed]
      Abstract:  MrImageStorage
      Transfer:  ImplicitVRLittleEndian
  Presentation Context:  5 [Proposed]
      Abstract:  CtImageStorage
      Transfer:  Jpeg2000Lossless
  Presentation Context:  7 [Proposed]
      Abstract:  CtImageStorage
      Transfer:  ImplicitVRLittleEndian
  Presentation Context:  9 [Proposed]
      Abstract:  EncapsulatedPdfStorage
      Transfer:  ExplicitVRLittleEndian
  Presentation Context:  11 [Proposed]
      Abstract:  EncapsulatedPdfStorage
      Transfer:  ImplicitVRLittleEndian
  Presentation Context:  13 [Proposed]
      Abstract:  BasicTextSrStorage
      Transfer:  ExplicitVRLittleEndian
  Presentation Context:  15 [Proposed]
      Abstract:  BasicTextSrStorage
      Transfer:  ImplicitVRLittleEndian

2024-07-25T08:57:56.926Z -- INFO -- SCU -> Association accept:
Application Context:     1.2.840.10008.3.1.1.1
Implementation Class:    1.2.826.0.1.3680043.10.854
Implementation Version:  DCMJS-DIMSE-V0.1
Maximum PDU Length:      262144
Called AE Title:         ANY-SCP
Calling AE Title:        SCU
Presentation Contexts:   8
  Presentation Context:  1 [Accept]
      Abstract:  MrImageStorage
      Transfer:  ExplicitVRBigEndian
  Presentation Context:  3 [Accept]
      Abstract:  MrImageStorage
      Transfer:  ImplicitVRLittleEndian
  Presentation Context:  5 [Accept]
      Abstract:  CtImageStorage
      Transfer:  Jpeg2000Lossless
  Presentation Context:  7 [Accept]
      Abstract:  CtImageStorage
      Transfer:  ImplicitVRLittleEndian
  Presentation Context:  9 [Accept]
      Abstract:  EncapsulatedPdfStorage
      Transfer:  ExplicitVRLittleEndian
  Presentation Context:  11 [Accept]
      Abstract:  EncapsulatedPdfStorage
      Transfer:  ImplicitVRLittleEndian
  Presentation Context:  13 [Accept]
      Abstract:  BasicTextSrStorage
      Transfer:  ExplicitVRLittleEndian
  Presentation Context:  15 [Accept]
      Abstract:  BasicTextSrStorage
      Transfer:  ImplicitVRLittleEndian

2024-07-25T08:57:56.997Z -- INFO -- SCU <- C-STORE RQ [HasDataset: true]
DIMSE Command Dataset:
==================================================
{"_vrMap":{},"CommandGroupLength":146,"AffectedSOPClassUID":"1.2.840.10008.5.1.4.1.1.4","CommandField":1,"MessageID":1,"Priority":0,"CommandDataSetType":514,"AffectedSOPInstanceUID":"1.2.826.0.1.3680043.2.1143.3638768091140812186843363535159947743"} [id: 1] [pc: 1]
2024-07-25T08:57:57.007Z -- INFO -- SCU -> C-STORE RSP [HasDataset: false]
DIMSE Command Dataset:
==================================================
{"CommandField":32769,"CommandDataSetType":257,"Status":0,"AffectedSOPClassUID":"1.2.840.10008.5.1.4.1.1.4","MessageIDBeingRespondedTo":1,"AffectedSOPInstanceUID":"1.2.826.0.1.3680043.2.1143.3638768091140812186843363535159947743"} [id: 1; status: Success] [pc: 1]
2024-07-25T08:57:57.034Z -- INFO -- SCU <- C-STORE RQ [HasDataset: true]
DIMSE Command Dataset:
==================================================
{"_vrMap":{},"CommandGroupLength":142,"AffectedSOPClassUID":"1.2.840.10008.5.1.4.1.1.4","CommandField":1,"MessageID":2,"Priority":0,"CommandDataSetType":514,"AffectedSOPInstanceUID":"1.3.46.670589.11.7002.9.1582062500000285221701.8.1.1.1.0.0.1"} [id: 2] [pc: 3]
Invalid vr type ox - using OW
2024-07-25T08:57:57.041Z -- INFO -- SCU -> C-STORE RSP [HasDataset: false]
DIMSE Command Dataset:
==================================================
{"CommandField":32769,"CommandDataSetType":257,"Status":0,"AffectedSOPClassUID":"1.2.840.10008.5.1.4.1.1.4","MessageIDBeingRespondedTo":2,"AffectedSOPInstanceUID":"1.3.46.670589.11.7002.9.1582062500000285221701.8.1.1.1.0.0.1"} [id: 2; status: Success] [pc: 3]
2024-07-25T08:57:57.053Z -- INFO -- SCU <- C-STORE RQ [HasDataset: true]
DIMSE Command Dataset:
==================================================
{"_vrMap":{},"CommandGroupLength":116,"AffectedSOPClassUID":"1.2.840.10008.5.1.4.1.1.2","CommandField":1,"MessageID":3,"Priority":0,"CommandDataSetType":514,"AffectedSOPInstanceUID":"1.2.840.113674.950809132337081.100"} [id: 3] [pc: 5]
2024-07-25T08:57:57.056Z -- INFO -- SCU -> C-STORE RSP [HasDataset: false]
DIMSE Command Dataset:
==================================================
{"CommandField":32769,"CommandDataSetType":257,"Status":0,"AffectedSOPClassUID":"1.2.840.10008.5.1.4.1.1.2","MessageIDBeingRespondedTo":3,"AffectedSOPInstanceUID":"1.2.840.113674.950809132337081.100"} [id: 3; status: Success] [pc: 5]
2024-07-25T08:57:57.065Z -- INFO -- SCU <- C-STORE RQ [HasDataset: true]
DIMSE Command Dataset:
==================================================
{"_vrMap":{},"CommandGroupLength":140,"AffectedSOPClassUID":"1.2.840.10008.5.1.4.1.1.104.1","CommandField":1,"MessageID":4,"Priority":0,"CommandDataSetType":514,"AffectedSOPInstanceUID":"1.2.276.0.7230010.3.1.4.368843532.32020.1619168794.980"} [id: 4] [pc: 9]
2024-07-25T08:57:57.069Z -- INFO -- SCU -> C-STORE RSP [HasDataset: false]
DIMSE Command Dataset:
==================================================
{"CommandField":32769,"CommandDataSetType":257,"Status":0,"AffectedSOPClassUID":"1.2.840.10008.5.1.4.1.1.104.1","MessageIDBeingRespondedTo":4,"AffectedSOPInstanceUID":"1.2.276.0.7230010.3.1.4.368843532.32020.1619168794.980"} [id: 4; status: Success] [pc: 9]
2024-07-25T08:57:57.074Z -- INFO -- SCU <- C-STORE RQ [HasDataset: true]
DIMSE Command Dataset:
==================================================
{"_vrMap":{},"CommandGroupLength":138,"AffectedSOPClassUID":"1.2.840.10008.5.1.4.1.1.88.11","CommandField":1,"MessageID":5,"Priority":0,"CommandDataSetType":514,"AffectedSOPInstanceUID":"1.2.276.0.7230010.3.1.4.1787205428.166.1117461927.34"} [id: 5] [pc: 13]
2024-07-25T08:57:57.077Z -- INFO -- SCU -> C-STORE RSP [HasDataset: false]
DIMSE Command Dataset:
==================================================
{"CommandField":32769,"CommandDataSetType":257,"Status":0,"AffectedSOPClassUID":"1.2.840.10008.5.1.4.1.1.88.11","MessageIDBeingRespondedTo":5,"AffectedSOPInstanceUID":"1.2.276.0.7230010.3.1.4.1787205428.166.1117461927.34"} [id: 5; status: Success] [pc: 13]
2024-07-25T08:57:57.133Z -- INFO -- SCU <- Association release request
2024-07-25T08:57:57.133Z -- INFO -- SCU -> Association release response
2024-07-25T08:57:57.181Z -- INFO -- SCU -> Connection closed

As you can see in the logs, the SCP accepted the proper presentation context IDs and the DICOM files were received, as expected. Would you mind checking again how you are handling your presentation IDs and figure why they are increasing?

@suoc
Copy link
Author

suoc commented Jul 26, 2024

I am using the scp example in the README document on the project homepage.
1721971078426

I will test with the new method you provided.

@PantelisGeorgiadis
Copy link
Owner

Hello @suoc,
Did you have the chance to verify this?

@suoc
Copy link
Author

suoc commented Aug 9, 2024

This issue has not been resolved, and since the peer device is closed source, I have made no progress through debugging on the receiving end, and no bugs have been found in the dcmjs-dimse source code. However, I have found a workaround for this issue, which is to clear the PresentationContexts when receiving the association request. The code is as follows:

if (association.implementationVersion.indexOf('NMSDICOM') != -1) {
    association.clearPresentationContexts();
    let pcId = association.addPresentationContext(StorageClass.MrImageStorage);
    association.addTransferSyntaxToPresentationContext(pcId, TransferSyntax.ExplicitVRLittleEndian);

    pcId = association.addPresentationContext(StorageClass.CtImageStorage);
    association.addTransferSyntaxToPresentationContext(pcId, TransferSyntax.ExplicitVRLittleEndian);

    pcId = association.addPresentationContext(StorageClass.UltrasoundImageStorage);
    association.addTransferSyntaxToPresentationContext(pcId, TransferSyntax.ExplicitVRLittleEndian);
}

@PantelisGeorgiadis
Copy link
Owner

Thank you for sharing part of your code @suoc. Is this code part of your SCP or SCU?

@suoc
Copy link
Author

suoc commented Aug 11, 2024

This code is part of my scp service

@PantelisGeorgiadis
Copy link
Owner

PantelisGeorgiadis commented Aug 12, 2024

Hello @suoc,
You should never alter the presentation contexts, during an association negotiation, in your SCP code. You should either accept or reject them. The code you sent explains why your presentation context IDs do not match with those sent by the SCU in your logs. The addPresentationContext function is internally increasing the presentation ID by two, creating a mismatch between the original IDs, sent by the SCU, and those sent back by your SCP, as part of the association acceptance. Rather than adding presentation contexts and transfer syntaxes to the proposed association object, you should iterate over the contexts and for each context, evaluate the proposed abstract syntax and the transfer syntaxes and accept them or reject them, accordingly.

Example:

associationRequested(association) {
    // Get the proposed presentation contexts
    const contexts = association.getPresentationContexts();

    // Iterate over the proposed presentation contexts
    contexts.forEach((c) => {
      
        // Get the proposed presentation context
        const context = association.getPresentationContext(c.id);

        // Get the abstract syntax of the presentation context and evaluate it
        const asUid = context.getAbstractSyntaxUid();

        // Get the proposed transfer syntax UIDs and iterate over them
        const tsIds = context.getTransferSyntaxUids();  
        tsIds.forEach((ts) => {
            // Evaluate the transfer syntax and accept or reject, accordingly
            context.setResult(PresentationContextResult.Accept, ts);
        });
    });

    // Accept the association
    this.sendAssociationAccept();
}

@PantelisGeorgiadis PantelisGeorgiadis added question Further information is requested and removed bug Something isn't working labels Aug 12, 2024
@suoc
Copy link
Author

suoc commented Aug 15, 2024

If I accept or reject presentation contexts in the normal way, the id will be wrong. I don't know where the problem is.Not all devices have this problem. Currently, it has been found that only the requests sent by this one device will have an id error.

@PantelisGeorgiadis
Copy link
Owner

Strange case... really! I tend to believe that it has to do with the SCU implementation but you already mentioned that other SCPs seem to able to handle it. Please let me know if you find anything that could help us debug the issue.

@PantelisGeorgiadis
Copy link
Owner

Hello @suoc! Have you managed to gather more information about this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants