DcmSCPPool, stopAfterCurrentAssociations and setOutputDirectory

All other questions regarding DCMTK

Moderator: Moderator Team

Post Reply
Message
Author
ruben.cruz
Posts: 43
Joined: Fri, 2019-05-03, 15:06

DcmSCPPool, stopAfterCurrentAssociations and setOutputDirectory

#1 Post by ruben.cruz »

Hi,

Have been creating using C (c++/cli)
at this moment we need to be able to start, stop and start again our scp to receive connections in a given port.

We have 2 problems that we can't find the solution yet.
We are using DcmSCPPool to start our listen() with given Configurations, we use this library because we can use the sportAfterCurrectAssociations() function to stop our listen, that was what we have read around in this forum to be the one of the proper ways to stop it. We choose this approach to "release" the port.


With that we can't setOutputDirectory, or there is a solution that we may have missed??
If there is other library we should use can you give us a tip of how to stop the listen()?

Michael Onken
DCMTK Developer
Posts: 2049
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

Re: DcmSCPPool, stopAfterCurrentAssociations and setOutputDirectory

#2 Post by Michael Onken »

Hi,

Before calling listen(), get the configuration from the pool class

Code: Select all

getConfig()
and call

Code: Select all

setConnectionBlockingMode(DUL_NOBLOCK)
on the configuration. That ensures that you do not listen infinitely if no connection request is received.

What happens if you call

Code: Select all

stopAfterCurrentAssociations()
on the DcmBaseSCPPool class?

There is no setOutputDirectory on the normal DcmSCP class used by the pool per default. You need to use the class DcmStorageSCP instead.

Best regards,
Michael

ruben.cruz
Posts: 43
Joined: Fri, 2019-05-03, 15:06

Re: DcmSCPPool, stopAfterCurrentAssociations and setOutputDirectory

#3 Post by ruben.cruz »

What happens if you call

Code: Select all

stopAfterCurrentAssociations()
on the DcmBaseSCPPool class?
it goes into to a state of waiting for a association to finish then it stops.
It "kind" does what we need, it stop the listen() and stop using the port, meaning i can restart if i need with new configurations.
This is the behaviour that we need and the DcmStorageSCP does not have a public function that can stop.

Michael Onken
DCMTK Developer
Posts: 2049
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

Re: DcmSCPPool, stopAfterCurrentAssociations and setOutputDirectory

#4 Post by Michael Onken »

Did you try using setConnectionBlockingMode(DUL_NOBLOCK) now?

ruben.cruz
Posts: 43
Joined: Fri, 2019-05-03, 15:06

Re: DcmSCPPool, stopAfterCurrentAssociations and setOutputDirectory

#5 Post by ruben.cruz »

Yes, and it does exactly what you said, then i have
OFStandard::sleep(5);
since i am testing it just stays there for 5 seconds to receive a incoming association.

Michael Onken
DCMTK Developer
Posts: 2049
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

Re: DcmSCPPool, stopAfterCurrentAssociations and setOutputDirectory

#6 Post by Michael Onken »

So, do I understand you correctly, that this solves the "stop listen" problem?

ruben.cruz
Posts: 43
Joined: Fri, 2019-05-03, 15:06

Re: DcmSCPPool, stopAfterCurrentAssociations and setOutputDirectory

#7 Post by ruben.cruz »

Yes,

with "stopAfterCurrentAssociations()" and "setConnectionBlockingMode(DUL_NOBLOCK)" it stops the listen.
but i need a way to "setOutputDirectory()".
DcmBaseSCPPool has the functions to stop but does not have a way to set the output directory.
DcmStorageSCP has a way to set the output directory but does not have functions to stop the "listen()".

Michael Onken
DCMTK Developer
Posts: 2049
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

Re: DcmSCPPool, stopAfterCurrentAssociations and setOutputDirectory

#8 Post by Michael Onken »

Hi,

you have to implement your own DcmSCP-derived class that you must use as template parameters when constructing the pool. Below is some sample code that I took from a project of mine; I modified the code to be unspecific, so I hope it still works. A class called StorageServer is constructed and instantiated in the very end. Here it is:

Code: Select all

#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
#include "dcmtk/dcmdata/dcdatset.h"
#include "dcmtk/dcmnet/scppool.h"
#include "dcmtk/dcmnet/scpthrd.h"

class StorageServerThread : public DcmThreadSCP
{

public:
    StorageServerThread()
        : DcmThreadSCP()
    {
    }

    virtual ~StorageServerThread() {}

    // overwrite method of DcmSCP to disable DcmSCP's standard handler
    OFCondition handleIncomingCommand(T_DIMSE_Message* incomingMsg, const DcmPresentationContextInfo& presInfo)
    {

        if (incomingMsg->CommandField == DIMSE_C_STORE_RQ)
        {
            // handle incoming C-STORE request
            DcmDataset* dset = NULL;
            return handleSTORERequest(incomingMsg->msg.CStoreRQ, presInfo.presentationContextID, dset);
        }
        else
        {
            return DcmSCP::handleIncomingCommand(incomingMsg, presInfo);
        }
    }

protected:
    /** Handle incoming storage request.
     */
    virtual OFCondition
    handleSTORERequest(T_DIMSE_C_StoreRQ& reqMessage, const T_ASC_PresentationContextID presID, DcmDataset*& reqDataset)
    {
        OFCondition result = receiveSTORERequest(reqMessage, presID, reqDataset);
        // Do whatever you like with dataset, e.g. store to disk to the desired directory
        // ...
        return result;
    }
};

class StorageServer : public DcmSCPPool<StorageServerThread>
{

public:
    StorageServer()
    {
        // Configure SCP, only port is required
        getConfig().setPort(11112);
        getConfig().setRespondWithCalledAETitle(OFTrue);
        setMaxThreads(20);
        getConfig().setConnectionBlockingMode(DUL_NOBLOCK);
        getConfig().setConnectionTimeout(10);

        // Add presentation context to be handled
        OFList<OFString> ts;
        ts.push_back(UID_LittleEndianExplicitTransferSyntax);
        ts.push_back(UID_LittleEndianImplicitTransferSyntax);
        ts.push_back(UID_BigEndianExplicitTransferSyntax);
        ts.push_back(UID_JPEGProcess14SV1TransferSyntax);
        ts.push_back(UID_JPEGProcess1TransferSyntax);
        for (size_t n = 0; n < numberOfDcmLongSCUStorageSOPClassUIDs; n++)
        {
            getConfig().addPresentationContext(dcmLongSCUStorageSOPClassUIDs[n], ts);
        }
        getConfig().addPresentationContext(UID_VerificationSOPClass, ts);
    }

    virtual ~StorageServer() {}

    virtual OFCondition listen() { return DcmSCPPool::listen(); }

    virtual void request_stop() { DcmBaseSCPPool::stopAfterCurrentAssociations(); }
};

// Now we can instantiate the class
StorageServer server; 

Maybe we should put this up as a howto in the support section.

Best regards,
Michael

P.S: Edit: I removed the StorageServerConfig since its not required in this version of the code.

ruben.cruz
Posts: 43
Joined: Fri, 2019-05-03, 15:06

Re: DcmSCPPool, stopAfterCurrentAssociations and setOutputDirectory

#9 Post by ruben.cruz »

Thank you so much for your help so far, the code is very usefull and we have been digging into it.

Now we would like to know how to handle the file to store it in a disered Directory.
We believe that maybe has something to do with "DcmFileFormat".
Can you give us a sample on how to handle properlly the file and store it in the desired directory?
We would later need to read the dataset and send it to diferent directories but if we could at least for now just throw to directory we have permissions would work.

Code: Select all

	virtual OFCondition
		handleSTORERequest(T_DIMSE_C_StoreRQ& reqMessage, const T_ASC_PresentationContextID presID, DcmDataset*& reqDataset)
	{
		OFCondition result = receiveSTORERequest(reqMessage, presID, reqDataset);
		// Do whatever you like with dataset, e.g. store to disk to the desired directory
		// ...
		
		return result;
	}

Michael Onken
DCMTK Developer
Posts: 2049
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

Re: DcmSCPPool, stopAfterCurrentAssociations and setOutputDirectory

#10 Post by Michael Onken »

Hi,

you can do the following within handleSTORERequest():

Code: Select all

    DcmFileFormat fileformat;
    *reqDataset = fileformat.getDataset();
    OFCondition result = receiveSTORERequest(...., reqDataset)
    if (result.good())
    {
        result = fileformat.save("/path/to/the/output_file.dcm");
        if (result.bad() {...}
   }
You can see more (possible) details in the implementation of the same method handleIncomingCommand() in DcmStorageSCP, which is used by the tool dcmrecv.

Best regards,
Michael

ruben.cruz
Posts: 43
Joined: Fri, 2019-05-03, 15:06

Re: DcmSCPPool, stopAfterCurrentAssociations and setOutputDirectory

#11 Post by ruben.cruz »

hi,
Thank you for the help! i just fixed what you send since it was not working for me

Code: Select all

	
		DcmFileFormat fileformat;
		*&reqDataset = fileformat.getDataset();
		OFCondition result = receiveSTORERequest(reqMessage, presID, reqDataset);
		if (result.good())
		{
			result = fileformat.saveFile("/path/to/the/output_file.dcm");
		}
ok, now i have other problem in a continuation of what is being done, The sender receives and error (Stored Failed...) following and aborted association.
What i think is that i am missing something on return of "handleIncomingCommand()", maybe a message/code of stored success or something. Can you help?

EDIT: i figure it out that maybe the solution is the use of "sendSTOREResponse()"

Michael Onken
DCMTK Developer
Posts: 2049
Joined: Fri, 2004-11-05, 13:47
Location: Oldenburg, Germany
Contact:

Re: DcmSCPPool, stopAfterCurrentAssociations and setOutputDirectory

#12 Post by Michael Onken »

Exactly, please see DcmStorageSCP as the perfect and complete example:)

ruben.cruz
Posts: 43
Joined: Fri, 2019-05-03, 15:06

Re: DcmSCPPool, stopAfterCurrentAssociations and setOutputDirectory

#13 Post by ruben.cruz »

@Michael Onken

i have a small problem i guess for this case creating a new topic would not be needed.

I have been trying to create new folders using :

Code: Select all

status = OFStandard::createDirectory(generatedDirName, directoryName  /* rootDir */);
before the combineDirAndFilename and fileformat.saveFile(..)

but it never creates new directories and the status never returns an error.

Do you have any tip on what i might be doing wrong?

i had no errors using straight
"System::IO::Directory::CreateDirectory(newFolder);"
but i would prefer to using dcmtk library

Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 1 guest