SVG5/SDCMSendImpl.cpp
2025-10-12 13:55:56 +09:00

1875 lines
61 KiB
C++

#include "SDCMSendImpl.h"
//#include "SThreadProgress.h"
#include <stdio.h>
#ifdef UNICODE
#undef UNICODE
#undef _UNICODE
#define UNICODE_DEFINED
#endif
#include "dcmtk/dcmdata/dcfilefo.h"
#include "dcmtk/dcmnet/diutil.h"
#include "dcmtk/dcmdata/dcxfer.h"
#include "dcmtk/dcmjpeg/djdecode.h" /* for JPEG decoders */
#include "dcmtk/dcmjpeg/djencode.h" /* for JPEG encoders */
#include "dcmtk/dcmjpls/djdecode.h" /* for JPEG-LS decoders */
#include "dcmtk/dcmjpls/djencode.h" /* for JPEG-LS encoders */
#include "dcmtk/dcmdata/dcrledrg.h" /* for RLE decoder */
#include "dcmtk/dcmdata/dcrleerg.h" /* for RLE encoder */
#include "dcmtk/dcmjpeg/dipijpeg.h" /* for dcmimage JPEG plugin */
#include "dcmtk/dcmnet/cond.h"
#ifdef UNICODE_DEFINED
#define UNICODE
#define _UNICODE
#undef UNICODE_DEFINED
#endif
#include <QFile>
#include <QThread>
#include <QElapsedTimer>
#include "cscallbacksendprogress.h"
/*
typedef struct {
void *callbackData;
T_DIMSE_StoreProgress *progress;
T_DIMSE_C_StoreRQ *request;
DIMSE_StoreUserCallback callback;
CSThread* pCallbackThread;
} DIMSE_PrivateUserContext;
*/
typedef struct _DIMSE_PrivateUserContext{
void *callbackData;
T_DIMSE_StoreProgress *progress;
T_DIMSE_C_StoreRQ *request;
DIMSE_StoreUserCallback callback;
CSCallback* pCallback;
CSDCMSendImpl* pThis;
T_ASC_Association *assoc;
bool bSendComplete;
} DIMSE_PrivateUserContext;
static void
privateUserCallback(void *callbackData, unsigned long bytes)
{
DIMSE_PrivateUserContext *ctx;
ctx = (DIMSE_PrivateUserContext*)callbackData;
ctx->progress->state = DIMSE_StoreProgressing;
ctx->progress->progressBytes = bytes;
ctx->progress->callbackCount++;
if (ctx->callback) {
ctx->callback(ctx->callbackData, ctx->progress, ctx->request);
}
}
#include "dcmtk/dcmdata/dcdict.h"
#include "dcmtk/dcmdata/dcdicent.h"
extern DCMTK_DCMDATA_EXPORT GlobalDcmDataDictionary dcmDataDict;
OFBool
isDataDictPresent()
{
/* is a data dictionary present */
return dcmDataDict.isDictionaryLoaded();
}
OFCondition CSDCMSendImpl::DIMSE_storeUser(
T_ASC_Association *assoc, T_ASC_PresentationContextID presId,
T_DIMSE_C_StoreRQ *request,
const char *imageFileName, DcmDataset *imageDataSet,
DIMSE_StoreUserCallback callback, void *callbackData,
T_DIMSE_BlockingMode blockMode, int timeout,
T_DIMSE_C_StoreRSP *response,
DcmDataset **statusDetail,
T_DIMSE_DetectedCancelParameters *checkForCancelParams,
long imageFileTotalBytes)
/*
* This function transmits data from a file or a dataset to an SCP. The transmission is
* conducted via network and using DIMSE C-STORE messages. Additionally, this function
* evaluates C-STORE-Response messages which were received from the SCP.
*
* Parameters:
* assoc - [in] The association (network connection to SCP).
* presId - [in] The ID of the presentation context which shall be used
* request - [in] Represents a DIMSE C-Store Request Message. Contains corresponding
* information, e.g. message ID, affected SOP class UID, etc.
* imageFileName - [in] The name of the file which is currently processed.
* imageDataSet - [in] The data set which is currently processed.
* callback - [in] Pointer to a function which shall be called to indicate progress.
* callbackData - [in] Pointer to data which shall be passed to the progress indicating function
* blockMode - [in] The blocking mode for receiving data (either DIMSE_BLOCKING or DIMSE_NONBLOCKING)
* timeout - [in] Timeout interval for receiving data. If the blocking mode is DIMSE_NONBLOCKING
* response - [out] Represents a DIMSE C-Store Response Message. Contains corresponding
* information, e.g. message ID being responded to, affected SOP class UID, etc.
* This variable contains in the end the C-STORE-RSP command which was received
* as a response to the C-STORE-RQ which was sent.
* statusDetail - [out] If a non-NULL value is passed this variable will in the end contain detailed
* information with regard to the status information which is captured in the status
* element (0000,0900) of the response message. Note that the value for element (0000,0900)
* is not contained in this return value but in response.
* checkForCancelParams - [out] Indicates, if a C-Cancel (Request) Message was encountered. Contains corresponding
* information, e.g. a boolean value if a corresponding message was encountered and the
* C-Cancel (Request) Message itself (in case it actually was encountered).
* imageFileTotalBytes - [in] The size of the file which is currently processed in bytes.
*/
{
OFCondition cond = EC_Normal;
T_DIMSE_Message req, rsp;
DIMSE_PrivateUserContext callbackCtx;
DIMSE_ProgressCallback privCallback = NULL;
T_DIMSE_StoreProgress progress;
/* if there is no image file or no data set, no data can be sent */
if (imageFileName == NULL && imageDataSet == NULL) return DIMSE_NULLKEY;
/* initialize the variables which represent DIMSE C-STORE request and DIMSE C-STORE response messages */
bzero((char*)&req, sizeof(req));
bzero((char*)&rsp, sizeof(rsp));
/* set corresponding values in the request message variable */
req.CommandField = DIMSE_C_STORE_RQ;
request->DataSetType = DIMSE_DATASET_PRESENT;
req.msg.CStoreRQ = *request;
/* set up callback routine which is used to indicate progress */
if (callback != NULL) {
/* in case the caller indicated that he has his own progress indicating */
/* function set some variables correspondingly so that this particular */
/* function will be called whenever progress shall be indicated. */
privCallback = privateUserCallback; /* function defined above */
callbackCtx.callbackData = callbackData;
progress.state = DIMSE_StoreBegin;
progress.callbackCount = 1;
progress.progressBytes = 0;
if (imageFileTotalBytes > 0) progress.totalBytes = imageFileTotalBytes;
else
{
if (imageFileName != NULL) progress.totalBytes = OFstatic_cast(long, OFStandard::getFileSize(imageFileName));
else progress.totalBytes = dcmGuessModalityBytes(request->AffectedSOPClassUID);
}
callbackCtx.progress = &progress;
callbackCtx.request = request;
callbackCtx.callback = callback;
/* execute initial callback */
callback(callbackData, &progress, request);
} else {
/* in case the caller does not have his own progress indicating function no */
/* corresponding function will be called when progress shall be indicated. */
privCallback = NULL;
}
/* send C-STORE-RQ message and instance data using file data or data set */
if (imageFileName != NULL) {
DcmDataset statusDetail;
cond = DIMSE_sendMessageUsingFileData(assoc, presId, &req,
&statusDetail, imageFileName, privCallback, &callbackCtx);
} else {
cond = DIMSE_sendMessageUsingMemoryData(assoc, presId, &req,
NULL, imageDataSet, privCallback, &callbackCtx);
}
if (cond != EC_Normal) {
return cond;
}
/* execute final callback */
if (callback) {
progress.state = DIMSE_StoreEnd;
progress.callbackCount++;
/* execute final callback */
callback(callbackData, &progress, request);
}
/* check if a C-CANCEL-RQ message was encountered earlier */
if (checkForCancelParams != NULL) {
checkForCancelParams->cancelEncountered = OFFalse;
}
/* try to receive C-STORE-RSP */
do
{
/* remember the ID of the presentation context in a local variable */
T_ASC_PresentationContextID thisPresId = presId;
/* try to receive a C-STORE-RSP over the network. */
cond = DIMSE_receiveCommand(assoc, blockMode, timeout,
&thisPresId, &rsp, statusDetail);
if (cond != EC_Normal) return cond;
/* if everything was successful so far, the rsp variable contains the command which */
/* was received check if we encountered a C-CANCEL-RQ; if so, set some variables */
if (checkForCancelParams != NULL && rsp.CommandField == DIMSE_C_CANCEL_RQ)
{
checkForCancelParams->cancelEncountered = OFTrue;
checkForCancelParams->req = rsp.msg.CCancelRQ;
checkForCancelParams->presId = thisPresId;
} else {
/* if we did not receive a C-CANCEL-RQ */
/* if we did also not encounter a C-STORE-RSP, something is wrong */
if (rsp.CommandField != DIMSE_C_STORE_RSP)
{
char buf[256];
sprintf(buf, "DIMSE: Unexpected Response Command Field: 0x%x", (unsigned)rsp.CommandField);
return makeDcmnetCondition(DIMSEC_UNEXPECTEDRESPONSE, OF_error, buf);
}
/* if we get to here, we received a C-STORE-RSP; store this message in the reference parameter */
*response = rsp.msg.CStoreRSP; // BoundsChecker warning !?
/* check if the response relates to the request which was sent earlier; if not, return an error */
if (response->MessageIDBeingRespondedTo != request->MessageID)
{
char buf2[256];
sprintf(buf2, "DIMSE: Unexpected Response MsgId: %d (expected: %d)", response->MessageIDBeingRespondedTo, request->MessageID);
return makeDcmnetCondition(DIMSEC_UNEXPECTEDRESPONSE, OF_error, buf2);
}
}
} while (checkForCancelParams != NULL && rsp.CommandField == DIMSE_C_CANCEL_RQ);
/* return result value */
return EC_Normal;
}
//OFLogger *m_pLoggerStoreSCU("store.log", OFLogger::TRACE_LOG_LEVEL);
CSDCMSendImpl::CSDCMSendImpl()
{
m_pCallback = NULL;
//COleDateTime dt = COleDateTime::GetCurrentTime();
char strLog[128];
memset(strLog, 0, 128);
//sprintf(strLog, "store_%04d%02d%02d.log", dt.GetYear(), dt.GetMonth(), dt.GetDay());
sprintf(strLog, "store.log");
OFLogger log = OFLog::getLogger(strLog);
m_pLoggerStoreSCU = &log;
m_pLoggerStoreSCU->setLogLevel(dcmtk::log4cplus::FATAL_LOG_LEVEL);
//m_pLoggerStoreSCU->Delete();
//m_pLoggerStoreSCU->Init("store.log");
//m_pLoggerStoreSCU->ClearLog();
//*m_pLoggerStoreSCU = OFLog::getLogger(strLog);
m_nMaxReceivePDULength = ASC_MAXIMUMPDUSIZE;
m_NetworkTransferSyntax = EXS_JPEGProcess14SV1;//EXS_Unknown;
m_bIdentResponse = false;
m_bHaltOnUnsuccessfulStore = OFTrue;
m_bUnsuccessfulStoreEncountered = OFFalse;
m_ReadMode = ERM_autoDetect;
m_bInventSOPInstanceInformation = OFFalse;
m_bCorrectUIDPadding = OFTrue;
m_DIMSEBlockMode = DIMSE_BLOCKING;
m_nLastStatusCode = STATUS_Success;
m_bAbortAssociation = false;
m_nTimeoutACSE = 0;
m_nTimeoutDIMSE = 0;
m_pNetwork = NULL;
m_pNetworkParams = NULL;
m_pAssoc = NULL;
m_bCombineProposedTransferSyntaxes = true;
m_bProposeOnlyRequiredPresentationContexts = false;
m_IdentMode = ASC_USER_IDENTITY_NONE;
m_nRepeatCount = 2;
m_pCurrentFileNameList = NULL;
// m_pNetClass = new CSDCMNetBase();
//register global JPEG decompression codecs
DJDecoderRegistration::registerCodecs();
// register global JPEG compression codecs
DJEncoderRegistration::registerCodecs();
// register JPEG-LS decompression codecs
DJLSDecoderRegistration::registerCodecs();
// register JPEG-LS compression codecs
DJLSEncoderRegistration::registerCodecs();
// register RLE compression codec
DcmRLEEncoderRegistration::registerCodecs();
// register RLE decompression codec
DcmRLEDecoderRegistration::registerCodecs();
}
CSDCMSendImpl::~CSDCMSendImpl()
{
}
void CSDCMSendImpl::Stop()
{
//cleanup global JPEG decompression codecs
DJDecoderRegistration::cleanup();
// cleanup global JPEG compression codecs
DJEncoderRegistration::cleanup();
// cleanup JPEG-LS decompression codecs
DJLSDecoderRegistration::cleanup();
// cleanup JPEG-LS compression codecs
DJLSEncoderRegistration::cleanup();
// cleanup RLE compression codec
DcmRLEEncoderRegistration::cleanup();
// cleanup RLE decompression codec
DcmRLEDecoderRegistration::cleanup();
}
int CSDCMSendImpl::InitNetwork(OFString strServerAETitle, OFString strClientAETitle, OFString strHostIP, int nPort, int nConnectType, int nBlock, int nTimeoutDIMSE, int nTimeoutACSE, E_TransferSyntax networkTransferSyntax)
{
SetServerInfo(strServerAETitle, strClientAETitle, strHostIP, nPort, nConnectType, nBlock);
return 0;
}
OFCondition CSDCMSendImpl::AddStoragePresentationContexts(T_ASC_Parameters *params, OFList<OFString> &sopClasses)
{
/*
* Each SOP Class will be proposed in two presentation contexts (unless
* the m_bCombineProposedTransferSyntaxes global variable is true).
* The command line specified a preferred transfer syntax to use.
* This prefered transfer syntax will be proposed in one
* presentation context and a set of alternative (fallback) transfer
* syntaxes will be proposed in a different presentation context.
*
* Generally, we prefer to use Explicitly encoded transfer syntaxes
* and if running on a Little Endian machine we prefer
* LittleEndianExplicitTransferSyntax to BigEndianTransferSyntax.
* Some SCP implementations will just select the first transfer
* syntax they support (this is not part of the standard) so
* organise the proposed transfer syntaxes to take advantage
* of such behaviour.
*/
// Which transfer syntax was preferred on the command line
OFString preferredTransferSyntax;
if (m_NetworkTransferSyntax == EXS_Unknown) {
/* gLocalByteOrder is defined in dcxfer.h */
if (gLocalByteOrder == EBO_LittleEndian) {
/* we are on a little endian machine */
//preferredTransferSyntax = UID_LittleEndianExplicitTransferSyntax;
//preferredTransferSyntax = UID_JPEGProcess1TransferSyntax;
preferredTransferSyntax = UID_LittleEndianExplicitTransferSyntax;
}
else {
/* we are on a big endian machine */
preferredTransferSyntax = UID_BigEndianExplicitTransferSyntax;
}
}
else {
DcmXfer xfer(m_NetworkTransferSyntax);
preferredTransferSyntax = xfer.getXferID();
//preferredTransferSyntax = UID_LittleEndianExplicitTransferSyntax;
}
OFListIterator(OFString) s_cur;
OFListIterator(OFString) s_end;
OFList<OFString> fallbackSyntaxes;
// - If little endian implicit is preferred, we don't need any fallback syntaxes
// because it is the default transfer syntax and all applications must support it.
// - If MPEG2 or MPEG4 is preferred, we don't want to propose any fallback solution
// because this is not required and we cannot decompress the movie anyway.
if ((m_NetworkTransferSyntax != EXS_LittleEndianImplicit) &&
(m_NetworkTransferSyntax != EXS_MPEG2MainProfileAtMainLevel) &&
(m_NetworkTransferSyntax != EXS_MPEG2MainProfileAtHighLevel) &&
(m_NetworkTransferSyntax != EXS_MPEG4HighProfileLevel4_1) &&
(m_NetworkTransferSyntax != EXS_MPEG4BDcompatibleHighProfileLevel4_1))
{
// fallbackSyntaxes.push_back(UID_LittleEndianExplicitTransferSyntax);
// fallbackSyntaxes.push_back(UID_BigEndianExplicitTransferSyntax);
// fallbackSyntaxes.push_back(UID_LittleEndianImplicitTransferSyntax);
// Remove the preferred syntax from the fallback list
fallbackSyntaxes.remove(preferredTransferSyntax);
}
// create a list of transfer syntaxes combined from the preferred and fallback syntaxes
OFList<OFString> combinedSyntaxes;
s_cur = fallbackSyntaxes.begin();
s_end = fallbackSyntaxes.end();
combinedSyntaxes.push_back(preferredTransferSyntax);
//sopClasses.push_back(preferredTransferSyntax);
OFString strCur;
while (s_cur != s_end)
{
strCur = *s_cur;
if (!IsaListMember(combinedSyntaxes, *s_cur))
{
// combinedSyntaxes.push_back(*s_cur);
// sopClasses.push_back(*s_cur);
}
++s_cur;
}
int nNumber = numberOfDcmShortSCUStorageSOPClassUIDs;
m_bProposeOnlyRequiredPresentationContexts = true;
if (!m_bProposeOnlyRequiredPresentationContexts) {
// add the (short list of) known storage SOP classes to the list
// the array of Storage SOP Class UIDs comes from dcuid.h
for (int i = 0; i < numberOfDcmShortSCUStorageSOPClassUIDs; i++)
{
OFString strTest = dcmShortSCUStorageSOPClassUIDs[i];
sopClasses.push_back(dcmShortSCUStorageSOPClassUIDs[i]);
}
}
// thin out the SOP classes to remove any duplicates
OFList<OFString> sops;
s_cur = sopClasses.begin();
s_end = sopClasses.end();
while (s_cur != s_end) {
strCur = *s_cur;
if (!IsaListMember(sops, *s_cur)) {
sops.push_back(*s_cur);
}
++s_cur;
}
// add a presentations context for each SOP class / transfer syntax pair
OFCondition cond = EC_Normal;
int pid = 1; // presentation context id
s_cur = sops.begin();
s_end = sops.end();
while (s_cur != s_end && cond.good()) {
strCur = *s_cur;
if (pid > 255)
{
OFLOG_ERROR(*m_pLoggerStoreSCU, "Too many presentation contexts");
return ASC_BADPRESENTATIONCONTEXTID;
}
if (m_bCombineProposedTransferSyntaxes)
{
cond = AddPresentationContext(params, pid, *s_cur, combinedSyntaxes);
pid += 2; /* only odd presentation context id's */
}
else
{
// SOP class with preferred transfer syntax
cond = AddPresentationContext(params, pid, *s_cur, preferredTransferSyntax);
pid += 2; /* only odd presentation context id's */
if (fallbackSyntaxes.size() > 0)
{
if (pid > 255)
{
OFLOG_ERROR(*m_pLoggerStoreSCU, "Too many presentation contexts");
return ASC_BADPRESENTATIONCONTEXTID;
}
// SOP class with fallback transfer syntax
cond = AddPresentationContext(params, pid, *s_cur, fallbackSyntaxes);
pid += 2; /* only odd presentation context id's */
}
}
++s_cur;
}
return cond;
}
OFBool CSDCMSendImpl::IsaListMember(OFList<OFString> &lst, OFString &s)
{
OFListIterator(OFString) cur = lst.begin();
OFListIterator(OFString) end = lst.end();
OFBool found = OFFalse;
while (cur != end && !found) {
found = (s == *cur);
++cur;
}
return found;
}
OFCondition CSDCMSendImpl::AddPresentationContext(T_ASC_Parameters *params, int presentationContextId, const OFString &abstractSyntax, const OFString &transferSyntax, T_ASC_SC_ROLE proposedRole)
{
const char *c_p = transferSyntax.c_str();
OFCondition cond = ASC_addPresentationContext(params, presentationContextId,
abstractSyntax.c_str(), &c_p, 1, proposedRole);
return cond;
}
OFCondition CSDCMSendImpl::AddPresentationContext(T_ASC_Parameters *params, int presentationContextId, const OFString &abstractSyntax, const OFList<OFString> &transferSyntaxList, T_ASC_SC_ROLE proposedRole)
{
// create an array of supported/possible transfer syntaxes
const char **transferSyntaxes = new const char*[transferSyntaxList.size()];
int transferSyntaxCount = 0;
OFListConstIterator(OFString) s_cur = transferSyntaxList.begin();
OFListConstIterator(OFString) s_end = transferSyntaxList.end();
while (s_cur != s_end) {
transferSyntaxes[transferSyntaxCount++] = (*s_cur).c_str();
++s_cur;
}
OFCondition cond = ASC_addPresentationContext(params, presentationContextId,
abstractSyntax.c_str(), transferSyntaxes, transferSyntaxCount, proposedRole);
delete[] transferSyntaxes;
return cond;
}
OFCondition CSDCMSendImpl::CheckUserIdentityResponse(T_ASC_Parameters *params)
{
if (params == NULL)
return ASC_NULLKEY;
/* So far it is only checked whether a requested, positive response was
actually received */
// In case we sent no user identity request, there are no checks at all
if ((m_IdentMode == ASC_USER_IDENTITY_NONE) || (!m_bIdentResponse))
return EC_Normal;
// If positive response was requested, we expect a corresponding response
if ((m_IdentMode == ASC_USER_IDENTITY_USER) || (m_IdentMode == ASC_USER_IDENTITY_USER_PASSWORD))
{
UserIdentityNegotiationSubItemAC *rsp = params->DULparams.ackUserIdentNeg;
if (rsp == NULL)
{
OFLOG_ERROR(*m_pLoggerStoreSCU, "User Identity Negotiation failed: Positive response requested but none received");
return ASC_USERIDENTIFICATIONFAILED;
}
}
return EC_Normal;
}
OFCondition CSDCMSendImpl::cstore(T_ASC_Association *assoc, const OFString &fname)
/*
* This function will process the given file as often as is specified by opt_repeatCount.
* "Process" in this case means "read file, send C-STORE-RQ, receive C-STORE-RSP".
*
* Parameters:
* assoc - [in] The association (network connection to another DICOM application).
* fname - [in] Name of the file which shall be processed.
*/
{
OFCondition cond = EC_Normal;
/* opt_repeatCount specifies how many times a certain file shall be processed */
int n = OFstatic_cast(int, m_nRepeatCount);
/* as long as no error occured and the counter does not equal 0 */
while ((cond.good()) && n-- && !(m_bHaltOnUnsuccessfulStore && m_bUnsuccessfulStoreEncountered))
{
/* process file (read file, send C-STORE-RQ, receive C-STORE-RSP) */
cond = storeSCU(assoc, fname.c_str());
if(cond.good())
{
break;
}
}
// we don't want to return an error code if --no-halt was specified.
if (!m_bHaltOnUnsuccessfulStore)
{
cond = EC_Normal;
}
/* return result value */
return cond;
}
OFCondition CSDCMSendImpl::storeSCU(T_ASC_Association *assoc, const char *fname)
/*
* This function will read all the information from the given file,
* figure out a corresponding presentation context which will be used
* to transmit the information over the network to the SCP, and it
* will finally initiate the transmission of all data to the SCP.
*
* Parameters:
* assoc - [in] The association (network connection to another DICOM application).
* fname - [in] Name of the file which shall be processed.
*/
{
DIC_US msgId = assoc->nextMsgID++;
T_ASC_PresentationContextID presID;
T_DIMSE_C_StoreRQ req;
T_DIMSE_C_StoreRSP rsp;
DIC_UI sopClass;
DIC_UI sopInstance;
DcmDataset *statusDetail = NULL;
m_bUnsuccessfulStoreEncountered = OFTrue; // assumption
OFLOG_INFO(*m_pLoggerStoreSCU, "Sending file: " << fname);
/* read information from file. After the call to DcmFileFormat::loadFile(...) the information */
/* which is encapsulated in the file will be available through the DcmFileFormat object. */
/* In detail, it will be available through calls to DcmFileFormat::getMetaInfo() (for */
/* meta header information) and DcmFileFormat::getDataset() (for data set information). */
DcmFileFormat dcmff;
OFCondition cond = dcmff.loadFile(fname, EXS_Unknown, EGL_noChange, DCM_MaxReadLength, m_ReadMode);
/* figure out if an error occured while the file was read*/
if (cond.bad())
{
//OFLOG_ERROR(*m_pLoggerStoreSCU, "Bad DICOM file: " << fname << ": " << cond.text());
return cond;
}
/* if required, invent new SOP instance information for the current data set (user option) */
if (m_bInventSOPInstanceInformation)
{
ReplaceSOPInstanceInformation(dcmff.getDataset());
}
/* figure out which SOP class and SOP instance is encapsulated in the file */
//if (!DU_findSOPClassAndInstanceInDataSet(dcmff.getDataset(), sopClass, sopInstance, m_bCorrectUIDPadding))
if (!DU_findSOPClassAndInstanceInDataSet(dcmff.getDataset(), sopClass, sizeof(sopClass), sopInstance, sizeof(sopInstance), m_bCorrectUIDPadding))
{
OFLOG_ERROR(*m_pLoggerStoreSCU, "No SOP Class or Instance UID in file: " << fname);
return DIMSE_BADDATA;
}
/* figure out which of the accepted presentation contexts should be used */
DcmXfer filexfer(dcmff.getDataset()->getOriginalXfer());
/* special case: if the file uses an unencapsulated transfer syntax (uncompressed
* or deflated explicit VR) and we prefer deflated explicit VR, then try
* to find a presentation context for deflated explicit VR first.
*/
if (filexfer.isNotEncapsulated() &&
m_NetworkTransferSyntax == EXS_DeflatedLittleEndianExplicit)
{
filexfer = EXS_DeflatedLittleEndianExplicit;
}
if (filexfer.getXfer() != EXS_Unknown)
presID = ASC_findAcceptedPresentationContextID(assoc, sopClass, filexfer.getXferID());
else
presID = ASC_findAcceptedPresentationContextID(assoc, sopClass);
// presID = ASC_findAcceptedPresentationContextID(assoc, sopClass);
if (presID == 0)
{
const char *modalityName = dcmSOPClassUIDToModality(sopClass);
if (!modalityName) modalityName = dcmFindNameOfUID(sopClass);
if (!modalityName) modalityName = "unknown SOP class";
OFLOG_ERROR(*m_pLoggerStoreSCU, "No presentation context for: (" << modalityName << ") " << sopClass);
return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
}
T_ASC_PresentationContext pc;
ASC_findAcceptedPresentationContext(assoc->params, presID, &pc);
DcmXfer netTransfer(pc.acceptedTransferSyntax);
/* if required, dump general information concerning transfer syntaxes */
if (m_pLoggerStoreSCU->isEnabledFor(OFLogger::INFO_LOG_LEVEL)) {
//register global JPEG decompression codecs
DJDecoderRegistration::registerCodecs();
// register global JPEG compression codecs
DJEncoderRegistration::registerCodecs();
DcmXfer fileTransfer(dcmff.getDataset()->getOriginalXfer());
OFLOG_INFO(*m_pLoggerStoreSCU, "Converting transfer syntax: " << fileTransfer.getXferName()
<< " -> " << netTransfer.getXferName());
}
dcmff.getDataset()->chooseRepresentation(netTransfer.getXfer(), NULL);
#ifdef ON_THE_FLY_COMPRESSION
#endif
/* prepare the transmission of data */
bzero(OFreinterpret_cast(char *, &req), sizeof(req));
req.MessageID = msgId;
strcpy(req.AffectedSOPClassUID, sopClass);
strcpy(req.AffectedSOPInstanceUID, sopInstance);
req.DataSetType = DIMSE_DATASET_PRESENT;
req.Priority = DIMSE_PRIORITY_LOW;
/* if required, dump some more general information */
OFLOG_INFO(*m_pLoggerStoreSCU, "Sending Store Request (MsgID " << msgId << ", " << dcmSOPClassUIDToModality(sopClass, "OT") << ")");
DIMSE_PrivateUserContext dpuc;
T_DIMSE_StoreProgress store_progress;
//dpuc.pCallbackThread = m_pCallbackThread;
dpuc.pCallback = m_pCallback;
dpuc.pThis = this;
dpuc.assoc = assoc;
dpuc.bSendComplete = false;
dpuc.progress = &store_progress;
m_DIMSEBlockMode = DIMSE_NONBLOCKING;
m_nTimeoutDIMSE = 5;
T_DIMSE_DetectedCancelParameters dcp;
/* finally conduct transmission of data */
cond = DIMSE_storeUser(assoc, presID, &req,
fname, dcmff.getDataset(), ProgressCallback, &dpuc,
m_DIMSEBlockMode, m_nTimeoutDIMSE,
&rsp, &statusDetail, &dcp, OFStandard::getFileSize(fname));
QElapsedTimer timeElapsed;
timeElapsed.start();
bool bError = false;
while(dpuc.bSendComplete==false && bError==false && store_progress.state!=DIMSE_StoreEnd)
{
QThread::usleep(100*1000);
if(timeElapsed.elapsed()>m_nTimeoutDIMSE*1000)
{
bError = true;
}
timeElapsed.restart();
}
if(bError==true)
{
}
if(cond.bad()==OFTrue)
{
return cond;
}
/*
cond = DIMSE_storeUser(assoc, presID, &req,
fname, dcmff.getDataset(), ProgressCallback, NULL,
m_DIMSEBlockMode, m_nTimeoutDIMSE,
&rsp, &statusDetail, NULL, OFStandard::getFileSize(fname));
*/
/*
* If store command completed normally, with a status
* of success or some warning then the image was accepted.
*/
if (cond == EC_Normal && (rsp.DimseStatus == STATUS_Success || DICOM_WARNING_STATUS(rsp.DimseStatus)))
{
m_bUnsuccessfulStoreEncountered = OFFalse;
}
/* remember the response's status for later transmissions of data */
m_nLastStatusCode = rsp.DimseStatus;
/* dump some more general information */
if (cond == EC_Normal)
{
OFString temp_str;
if (m_pLoggerStoreSCU->isEnabledFor(OFLogger::DEBUG_LOG_LEVEL))
{
OFLOG_INFO(*m_pLoggerStoreSCU, "Received Store Response");
//OFLOG_DEBUG(*m_pLoggerStoreSCU, DIMSE_dumpMessage(temp_str, rsp, DIMSE_INCOMING, NULL, presID));
}
else {
OFLOG_INFO(*m_pLoggerStoreSCU, "Received Store Response (" << DU_cstoreStatusString(rsp.DimseStatus) << ")");
}
if (m_pLoggerStoreSCU->isEnabledFor(OFLogger::TRACE_LOG_LEVEL))
{
OFLOG_ERROR(*m_pLoggerStoreSCU, "Dump dcm file: " << fname << ":" << OFendl << DimseCondition::dump(temp_str, cond));
}
}
else
{
OFString temp_str;
OFLOG_ERROR(*m_pLoggerStoreSCU, "Store Failed, file: " << fname << ":" << OFendl << DimseCondition::dump(temp_str, cond));
}
/* dump status detail information if there is some */
if (statusDetail != NULL) {
OFLOG_DEBUG(*m_pLoggerStoreSCU, "Status Detail:" << OFendl << DcmObject::PrintHelper(*statusDetail));
delete statusDetail;
}
/* return */
return cond;
}
void CSDCMSendImpl::ReplaceSOPInstanceInformation(DcmDataset *dataset)
{
// static OFCmdUnsignedInt patientCounter = 0;
// static OFCmdUnsignedInt studyCounter = 0;
// static OFCmdUnsignedInt seriesCounter = 0;
static OFCmdUnsignedInt imageCounter = 0;
// static OFString seriesInstanceUID;
// static OFString seriesNumber;
// static OFString studyInstanceUID;
// static OFString studyID;
// static OFString accessionNumber;
// static OFString patientID;
// static OFString patientName;
//
// if (seriesInstanceUID.empty()) seriesInstanceUID = makeUID(SITE_SERIES_UID_ROOT, OFstatic_cast(int, seriesCounter));
// if (seriesNumber.empty()) seriesNumber = intToString(OFstatic_cast(int, seriesCounter));
// if (studyInstanceUID.empty()) studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, OFstatic_cast(int, studyCounter));
// if (studyID.empty()) studyID = studyIDPrefix + intToString(OFstatic_cast(int, secondsSince1970())) + intToString(OFstatic_cast(int, studyCounter));
// if (accessionNumber.empty()) accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString(OFstatic_cast(int, studyCounter));
// if (patientID.empty()) patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString(OFstatic_cast(int, patientCounter));
// if (patientName.empty()) patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString(OFstatic_cast(int, patientCounter));
//
// if (imageCounter >= opt_inventSeriesCount) {
// imageCounter = 0;
// seriesCounter++;
// seriesInstanceUID = makeUID(SITE_SERIES_UID_ROOT, OFstatic_cast(int, seriesCounter));
// seriesNumber = intToString(OFstatic_cast(int, seriesCounter));
// }
// if (seriesCounter >= opt_inventStudyCount) {
// seriesCounter = 0;
// studyCounter++;
// studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, OFstatic_cast(int, studyCounter));
// studyID = studyIDPrefix + intToString(secondsSince1970()) + intToString(OFstatic_cast(int, studyCounter));
// accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString(OFstatic_cast(int, studyCounter));
// }
// if (studyCounter >= opt_inventPatientCount) {
// // we create as many patients as necessary */
// studyCounter = 0;
// patientCounter++;
// patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString(OFstatic_cast(int, patientCounter));
// patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString(OFstatic_cast(int, patientCounter));
// }
//
// OFString sopInstanceUID = makeUID(SITE_INSTANCE_UID_ROOT, OFstatic_cast(int, imageCounter));
// OFString imageNumber = intToString(OFstatic_cast(int, imageCounter));
//
// OFLOG_INFO(*m_pLoggerStoreSCU, "Inventing Identifying Information ("
// << "pa" << patientCounter << ", st" << studyCounter
// << ", se" << seriesCounter << ", im" << imageCounter << "):");
// OFLOG_INFO(*m_pLoggerStoreSCU, " PatientName=" << patientName);
// OFLOG_INFO(*m_pLoggerStoreSCU, " PatientID=" << patientID);
// OFLOG_INFO(*m_pLoggerStoreSCU, " StudyInstanceUID=" << studyInstanceUID);
// OFLOG_INFO(*m_pLoggerStoreSCU, " StudyID=" << studyID);
// OFLOG_INFO(*m_pLoggerStoreSCU, " SeriesInstanceUID=" << seriesInstanceUID);
// OFLOG_INFO(*m_pLoggerStoreSCU, " SeriesNumber=" << seriesNumber);
// OFLOG_INFO(*m_pLoggerStoreSCU, " SOPInstanceUID=" << sopInstanceUID);
// OFLOG_INFO(*m_pLoggerStoreSCU, " ImageNumber=" << imageNumber);
//
// updateStringAttributeValue(dataset, DCM_PatientName, patientName);
// updateStringAttributeValue(dataset, DCM_PatientID, patientID);
// updateStringAttributeValue(dataset, DCM_StudyInstanceUID, studyInstanceUID);
// updateStringAttributeValue(dataset, DCM_StudyID, studyID);
// updateStringAttributeValue(dataset, DCM_SeriesInstanceUID, seriesInstanceUID);
// updateStringAttributeValue(dataset, DCM_SeriesNumber, seriesNumber);
// updateStringAttributeValue(dataset, DCM_SOPInstanceUID, sopInstanceUID);
// updateStringAttributeValue(dataset, DCM_InstanceNumber, imageNumber);
imageCounter++;
}
void CSDCMSendImpl::ProgressCallback(void * callbackData, T_DIMSE_StoreProgress *progress, T_DIMSE_C_StoreRQ * req)
{
//TRACE("Send Bytes: %d\r\n", progress->progressBytes);
DIMSE_PrivateUserContext* pPrivate = (DIMSE_PrivateUserContext*)callbackData;
//T_ASC_Association *assoc = pPrivate->assoc;
if (pPrivate->pCallback != NULL)
{
CALLBACK_STATE(pPrivate->pCallback, progress->progressBytes, progress->totalBytes);
}
CSDCMSendImpl* pThis = pPrivate->pThis;
OFLogger* pLog = pThis->GetLogger();
if (progress->state == DIMSE_StoreBegin)
{
OFString str;
OFLOG_DEBUG(*pLog, DIMSE_dumpMessage(str, *req, DIMSE_OUTGOING));
}
// We can't use oflog for the pdu output, but we use a special logger for
// generating this output. If it is set to level "INFO" we generate the
// output, if it's set to "DEBUG" then we'll assume that there is debug output
// generated for each PDU elsewhere.
//OFLogger progressLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION ".progress");
//if (progressLogger.getChainedLogLevel() == OFLogger::INFO_LOG_LEVEL) {
switch (progress->state) {
case DIMSE_StoreBegin:
break;
case DIMSE_StoreEnd:
pPrivate->bSendComplete = true;
if (pPrivate->pCallback != NULL)
{
CALLBACK_STATE(pPrivate->pCallback, progress->progressBytes, progress->totalBytes);
//CALLBACK_COMPLETE(pPrivate->pCallback);
}
break;
default:
{
}
break;
}
//COUT.flush();
//}
}
/*
void CSDCMSendImpl::ProgressCallback(void * callbackData, T_DIMSE_StoreProgress *progress, T_DIMSE_C_StoreRQ * req)
{
//TRACE("Send Bytes: %d\r\n", progress->progressBytes);
DIMSE_PrivateUserContext* pPrivate = (DIMSE_PrivateUserContext*)callbackData;
if(pPrivate->pCallbackThread!=NULL)
{
pPrivate->pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_PROGRESS, (WPARAM)progress->progressBytes, (LPARAM)progress->totalBytes);
}
if (progress->state == DIMSE_StoreBegin)
{
OFString str;
//OFLOG_DEBUG(*m_pLoggerStoreSCU, DIMSE_dumpMessage(str, *req, DIMSE_OUTGOING));
}
// We can't use oflog for the pdu output, but we use a special logger for
// generating this output. If it is set to level "INFO" we generate the
// output, if it's set to "DEBUG" then we'll assume that there is debug output
// generated for each PDU elsewhere.
//OFLogger progressLogger = OFLog::getLogger("dcmtk.apps." OFFIS_CONSOLE_APPLICATION ".progress");
//if (progressLogger.getChainedLogLevel() == OFLogger::INFO_LOG_LEVEL) {
switch (progress->state) {
case DIMSE_StoreBegin:
break;
case DIMSE_StoreEnd:
if(pPrivate->pCallbackThread!=NULL)
{
pPrivate->pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_PROGRESS, (WPARAM)progress->totalBytes, (LPARAM)progress->totalBytes);
}
break;
default:
break;
}
//COUT.flush();
//}
}
*/
OFBool CSDCMSendImpl::FindSOPClassAndInstanceInFile(const char *fname, char *sopClass, char *sopInstance)
{
DcmFileFormat dcmff;
DcmDataset* pDcmDataset = NULL;
OFCondition cond = dcmff.loadFile(fname, EXS_Unknown, EGL_noChange, DCM_MaxReadLength, m_ReadMode);
if (cond.bad()==OFTrue)
return OFFalse;
pDcmDataset = dcmff.getDataset();
pDcmDataset->loadAllDataIntoMemory();
DIC_UI uisopClass;
DIC_UI uisopInstance;
/* look in the meta-header first */
//OFBool found = DU_findSOPClassAndInstanceInDataSet((DcmItem *)ff.getMetaInfo(), sopClass, sopInstance, m_bCorrectUIDPadding);
OFBool found = DU_findSOPClassAndInstanceInDataSet(pDcmDataset, uisopClass, sizeof(uisopClass), uisopInstance, sizeof(uisopInstance), m_bCorrectUIDPadding);
int nLength = 0;
nLength = strlen(uisopClass);
memcpy(sopClass, uisopClass, nLength);
nLength = strlen(uisopInstance);
memcpy(sopInstance, uisopInstance, nLength);
if (!found)
{
//found = DU_findSOPClassAndInstanceInDataSet(ff.getDataset(), sopClass, sopInstance, m_bCorrectUIDPadding);
found = DU_findSOPClassAndInstanceInDataSet(pDcmDataset, uisopClass, sizeof(uisopClass), uisopInstance, sizeof(uisopInstance), m_bCorrectUIDPadding);
OFString strSOPClassUID;
pDcmDataset->findAndGetOFString(DCM_SOPClassUID, strSOPClassUID);
}
dcmff.clear();
pDcmDataset->clear();
return found;
}
void CSDCMSendImpl::SetAETitle(OFString strAETitle)
{
m_strAETitle = strAETitle;
}
void CSDCMSendImpl::SetServerInfo(OFString strServerAETitle, OFString strClientAETitle, OFString strIP, int nPort, int nConnectionType, int nBlockingMethod)
{
m_strAETitle = strClientAETitle;
m_strServerAETitle = strServerAETitle;
m_strHostIP = strIP;
m_nPort = nPort;
m_ConnectType = (SNETWORK_CONNECTION)nConnectionType;
m_BlockMode = (SNETWORK_BLOCK_MODE)nBlockingMethod;
}
void CSDCMSendImpl::SetServerInfo(QString strServerAETitle, QString strClientAETitle, QString strIP, int nPort, int nConnectionType, int nBlockingMethod)
{
m_strAETitle = strClientAETitle.toStdString().c_str();
m_strServerAETitle = strServerAETitle.toStdString().c_str();
m_strHostIP = strIP.toStdString().c_str();
m_nPort = nPort;
m_ConnectType = (SNETWORK_CONNECTION)nConnectionType;
m_BlockMode = (SNETWORK_BLOCK_MODE)nBlockingMethod;
}
void CSDCMSendImpl::AddImageFilename(OFString strFilename)
{
m_ImageFileNameList.push_back(strFilename);
}
void CSDCMSendImpl::AddMpegFilename(OFString strFilename)
{
m_MpegFileNameList.push_back(strFilename);
}
void CSDCMSendImpl::ClearFileList()
{
ClearImageFileList();
ClearMpegFileList();
}
void CSDCMSendImpl::ClearImageFileList()
{
m_ImageFileNameList.clear();
}
void CSDCMSendImpl::ClearMpegFileList()
{
m_MpegFileNameList.clear();
}
void CSDCMSendImpl::SetCurrentFilenameList(int nCurrent)
{
if(nCurrent==0)
{
m_pCurrentFileNameList = NULL;
}
else if(nCurrent==1)
{
m_pCurrentFileNameList = &m_ImageFileNameList;
}
else if(nCurrent==2)
{
m_pCurrentFileNameList = &m_MpegFileNameList;
}
}
int CSDCMSendImpl::GetImageFileCount()
{
return m_ImageFileNameList.size();
}
int CSDCMSendImpl::GetMpegFileCount()
{
return m_MpegFileNameList.size();
}
vector<QString> CSDCMSendImpl::Send(CSCallback* pCallback, int nTimeoutDIMSE, int nTimeoutACSE, E_TransferSyntax networkTransferSyntax)
{
m_pCallback = pCallback;
if(nTimeoutDIMSE>0)
{
m_nTimeoutDIMSE = nTimeoutDIMSE;
}
if(nTimeoutACSE>0)
{
m_nTimeoutACSE = nTimeoutACSE;
}
dcmConnectionTimeout.set(m_nTimeoutACSE);
m_NetworkTransferSyntax = networkTransferSyntax;
//PostThreadMessage(WM_DCM_SEND, NULL, NULL);
return OnDCMSend();
}
/*
int CSDCMSendImpl::Send(CSThread* pCallbackThread, int nTimeoutDIMSE, int nTimeoutACSE, E_TransferSyntax networkTransferSyntax)
{
m_pCallbackThread = pCallbackThread;
m_nTimeoutDIMSE = nTimeoutDIMSE;
m_nTimeoutACSE = nTimeoutACSE;
m_NetworkTransferSyntax = networkTransferSyntax;
PostThreadMessage(WM_DCM_SEND, NULL, NULL);
return 0;
}
*/
vector<QString> CSDCMSendImpl::OnDCMSend()
{
vector<QString> listSendCompleteFile;
//SetSleep(10);
const char* pServerAETitle = NULL;
const char* pClientAETitle = NULL;
OFString strServerIPnPort;
// char* pPeer = NULL;
OFBool bSecureConnection = false;
OFList<OFString> sopClassUIDList; // the list of SOP classes
OFList<OFString> sopInstanceUIDList; // the list of SOP instances
OFCondition cond;
int nLength = 0;
char sopClassUID[128];
char sopInstanceUID[128];
OFString temp_str;
//fileNameList.push_back("test.dcm");
if(m_pCurrentFileNameList->size()==0)
{
return listSendCompleteFile;
}
OFListIterator(OFString) iterFirst = m_pCurrentFileNameList->begin();
//FindSOPClassAndInstanceInFile("mpeg_test.dcm", sopClassUID, sopInstanceUID);
memset(sopClassUID, 0, 128);
memset(sopInstanceUID, 0, 128);
bool bFindInstanceUID = false;
while(bFindInstanceUID==false && iterFirst!=m_pCurrentFileNameList->end())
{
OFString strFirstDcmFile = *iterFirst;
FindSOPClassAndInstanceInFile(strFirstDcmFile.c_str(), sopClassUID, sopInstanceUID);
iterFirst++;
}
pServerAETitle = m_strServerAETitle.c_str();
pClientAETitle = m_strAETitle.c_str();
//m_nTimeoutACSE = 10;
//DCM_dcmnetLogger = *m_pLoggerStoreSCU;
OFLogger log = OFLog::getLogger("store.log");
m_pLoggerStoreSCU = &log;
m_pLoggerStoreSCU->setLogLevel(dcmtk::log4cplus::FATAL_LOG_LEVEL);
dcmConnectionTimeout.set(m_nTimeoutACSE);
OFLOG_INFO(*m_pLoggerStoreSCU, "------------------------ DICOM Store Start --------------------------------------------");
CALLBACK_INFO(m_pCallback, INITIALIZE_NETWORK);
cond = ASC_initializeNetwork(NET_REQUESTOR, 0, m_nTimeoutACSE, &m_pNetwork);
if (cond.bad())
{
CALLBACK_ERROR(m_pCallback, INITIALIZE_NETWORK);
return listSendCompleteFile;
}
CALLBACK_INFO(m_pCallback, CREATE_ASSOCIATION_PARAMETERS);
/* initialize asscociation parameters, i.e. create an instance of T_ASC_Parameters*. */
cond = ASC_createAssociationParameters(&m_pNetworkParams, m_nMaxReceivePDULength);
if (cond.bad())
{
CALLBACK_ERROR(m_pCallback, CREATE_ASSOCIATION_PARAMETERS);
return listSendCompleteFile;
}
CALLBACK_INFO(m_pCallback, SET_APTITLES);
/* sets this application's title and the called application's title in the params */
/* structure. The default values to be set here are "STORESCU" and "ANY-SCP". */
cond = ASC_setAPTitles(m_pNetworkParams, pClientAETitle, pServerAETitle, NULL);
if (cond.bad())
{
CALLBACK_ERROR(m_pCallback, SET_APTITLES);
return listSendCompleteFile;
}
CALLBACK_INFO(m_pCallback, SET_TRANSPORT_LAYER_TYPE);
cond = ASC_setTransportLayerType(m_pNetworkParams, bSecureConnection);
if (cond.bad())
{
CALLBACK_ERROR(m_pCallback, SET_TRANSPORT_LAYER_TYPE);
//Sleep(10);
return listSendCompleteFile;
}
/* Figure out the presentation addresses and copy the */
/* corresponding values into the association parameters.*/
gethostname(m_LocalHost, sizeof(m_LocalHost) - 1);
// sprintf(peerHost, "%s:%d", pPeer, OFstatic_cast(int, m_nPort));
//sprintf(m_LocalHost, "192.168.123.23");
char* pStrServerIPnPort = new char[1024];
sprintf(pStrServerIPnPort, "%s:%d", m_strHostIP.c_str(), m_nPort);
strServerIPnPort = pStrServerIPnPort;
delete[] pStrServerIPnPort;
nLength = strServerIPnPort.length();
const char* pData = NULL;
pData = strServerIPnPort.c_str();
memset(m_PeerHost, 0, sizeof(m_PeerHost));
memcpy(m_PeerHost, pData, nLength);
CALLBACK_INFO(m_pCallback, SET_PRESENTATION_ADDRESSES);
cond = ASC_setPresentationAddresses(m_pNetworkParams, m_LocalHost, m_PeerHost);
if (cond.bad())
{
CALLBACK_ERROR(m_pCallback, SET_TRANSPORT_LAYER_TYPE);
//Sleep(10);
return listSendCompleteFile;
}
sopClassUIDList.push_back(sopClassUID);
sopInstanceUIDList.push_back(sopInstanceUID);
CALLBACK_INFO(m_pCallback, ADD_STORAGE_PRESENTATION_CONTEXTS);
cond = AddStoragePresentationContexts(m_pNetworkParams, sopClassUIDList);
if (cond.bad())
{
CALLBACK_ERROR(m_pCallback, ADD_STORAGE_PRESENTATION_CONTEXTS);
return listSendCompleteFile;
}
//#include "dcmtk\dcmnet\dul.h"
// m_pNetworkParams->DULparams.requestedPresentationContext;
CALLBACK_INFO(m_pCallback, REQUEST_ASSOCIATION);
cond = ASC_requestAssociation(m_pNetwork, m_pNetworkParams, &m_pAssoc);
if (cond.bad())
{
if (cond == DUL_ASSOCIATIONREJECTED)
{
CALLBACK_ERROR(m_pCallback, REJECTED_ASSOCIATION);
T_ASC_RejectParameters rej;
ASC_getRejectParameters(m_pNetworkParams, &rej);
OFLOG_FATAL(*m_pLoggerStoreSCU, "Association Rejected:" << OFendl << ASC_printRejectParameters(temp_str, &rej));
}
else
{
CALLBACK_ERROR(m_pCallback, UNKNOWN_ERROR_ASSOCIATION);
OFLOG_FATAL(*m_pLoggerStoreSCU, "Association Rejected:" << OFendl << cond.text());
if (m_pAssoc != NULL)
{
cond = ASC_destroyAssociation(&m_pAssoc);
}
if (m_pNetwork != NULL)
{
cond = ASC_dropNetwork(&m_pNetwork);
}
}
return listSendCompleteFile;
}
CALLBACK_INFO(m_pCallback, COUNT_ACCEPTED_PRESENTATION_CONTEXTS);
if (ASC_countAcceptedPresentationContexts(m_pNetworkParams) == 0)
{
OFLOG_FATAL(*m_pLoggerStoreSCU, "No Acceptable Presentation Contexts");
CALLBACK_ERROR(m_pCallback, COUNT_ACCEPTED_PRESENTATION_CONTEXTS);
if (m_pAssoc != NULL)
{
cond = ASC_destroyAssociation(&m_pAssoc);
}
if (m_pNetwork != NULL)
{
cond = ASC_dropNetwork(&m_pNetwork);
}
return listSendCompleteFile;
}
CALLBACK_INFO(m_pCallback, CHECK_USER_IDENTITY_RESPONSE);
cond = CheckUserIdentityResponse(m_pNetworkParams);
if (cond.bad())
{
OFLOG_FATAL(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
CALLBACK_ERROR(m_pCallback, CHECK_USER_IDENTITY_RESPONSE);
if (m_pAssoc != NULL)
{
cond = ASC_destroyAssociation(&m_pAssoc);
}
if (m_pNetwork != NULL)
{
cond = ASC_dropNetwork(&m_pNetwork);
}
return listSendCompleteFile;
}
cond = EC_Normal;
OFListIterator(OFString) iter = m_pCurrentFileNameList->begin();
OFListIterator(OFString) enditer = m_pCurrentFileNameList->end();
CALLBACK_INFO(m_pCallback, TRY_STORE_SCU);
bool bExitSend = false;
CSCallbackSendProgress* pCallbackSendProgress = (CSCallbackSendProgress*)m_pCallback;
if (iter != enditer)
{
while ((iter != enditer) && cond.good() && (bExitSend=pCallbackSendProgress->IsExitSend())==false)
{
cond = cstore(m_pAssoc, *iter);
if (cond.good())
{
OFString strTmpFile = *iter;
QString strFilename = strTmpFile.c_str();
listSendCompleteFile.push_back(strFilename);
cond = EC_Normal;
m_bUnsuccessfulStoreEncountered = false;
usleep(100);
}
else
{
int a=0;
}
++iter;
}
}
else
{
cond = cstore(m_pAssoc, *iter);
}
if(bExitSend==true)
{
int a=0;
}
if (cond == EC_Normal)
{
if (m_bAbortAssociation == true)
{
OFLOG_INFO(*m_pLoggerStoreSCU, "Aborting Association");
CALLBACK_INFO(m_pCallback, ABORT_ASSOCIATION);
cond = ASC_abortAssociation(m_pAssoc);
if (cond.bad())
{
OFLOG_ERROR(*m_pLoggerStoreSCU, "Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
CALLBACK_ERROR(m_pCallback, ABORT_ASSOCIATION);
return listSendCompleteFile;
}
}
else {
/* release association */
OFLOG_INFO(*m_pLoggerStoreSCU, "Releasing Association");
CALLBACK_INFO(m_pCallback, RELEASE_ASSOCIATION);
cond = ASC_releaseAssociation(m_pAssoc);
if (cond.bad())
{
OFLOG_FATAL(*m_pLoggerStoreSCU, "Association Release Failed: " << DimseCondition::dump(temp_str, cond));
CALLBACK_ERROR(m_pCallback, RELEASE_ASSOCIATION);
return listSendCompleteFile;
}
}
CALLBACK_INFO(m_pCallback, DESTROY_ASSOCIATION);
/* destroy the association, i.e. free memory of T_ASC_Association* structure. This */
/* call is the counterpart of ASC_requestAssociation(...) which was called above. */
cond = ASC_destroyAssociation(&m_pAssoc);
if (cond.bad())
{
OFLOG_FATAL(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
CALLBACK_ERROR(m_pCallback, DESTROY_ASSOCIATION);
return listSendCompleteFile;
}
/* drop the network, i.e. free memory of T_ASC_Network* structure. This call */
/* is the counterpart of ASC_initializeNetwork(...) which was called above. */
CALLBACK_INFO(m_pCallback, DROP_NETWORK);
cond = ASC_dropNetwork(&m_pNetwork);
if (cond.bad())
{
OFLOG_INFO(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
CALLBACK_INFO(m_pCallback, DROP_NETWORK);
return listSendCompleteFile;
}
OFLOG_INFO(*m_pLoggerStoreSCU, "------------------------------------ End --------------------------------------------");
//CALLBACK_COMPLETE(m_pCallback);
//SetSleep(10);
return listSendCompleteFile;
}
else if (cond == DUL_PEERREQUESTEDRELEASE)
{
CALLBACK_INFO(m_pCallback, PEER_REQUESTED_RELEASE);
OFLOG_ERROR(*m_pLoggerStoreSCU, "Protocol Error: Peer requested release (Aborting)");
OFLOG_INFO(*m_pLoggerStoreSCU, "Aborting Association");
CALLBACK_INFO(m_pCallback, ABORT_ASSOCIATION);
cond = ASC_abortAssociation(m_pAssoc);
if (cond.bad())
{
OFLOG_ERROR(*m_pLoggerStoreSCU, "Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
CALLBACK_ERROR(m_pCallback, ABORT_ASSOCIATION);
return listSendCompleteFile;
}
}
else if (cond == DUL_PEERABORTEDASSOCIATION)
{
CALLBACK_ERROR(m_pCallback, PEER_ABORTED_ASSOCIATION);
OFLOG_INFO(*m_pLoggerStoreSCU, "Peer Aborted Association");
}
else
{
CALLBACK_ERROR(m_pCallback, TRY_STORE_SCU);
OFLOG_ERROR(*m_pLoggerStoreSCU, "Store SCU Failed: " << DimseCondition::dump(temp_str, cond));
OFLOG_INFO(*m_pLoggerStoreSCU, "Aborting Association");
CALLBACK_INFO(m_pCallback, ABORT_ASSOCIATION);
if(cond.code()!=526)
{
cond = ASC_abortAssociation(m_pAssoc);
}
if (cond.bad())
{
CALLBACK_ERROR(m_pCallback, ABORT_ASSOCIATION);
OFLOG_ERROR(*m_pLoggerStoreSCU, "Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
CALLBACK_INFO(m_pCallback, DESTROY_ASSOCIATION);
cond = ASC_destroyAssociation(&m_pAssoc);
return listSendCompleteFile;
}
}
CALLBACK_INFO(m_pCallback, DESTROY_ASSOCIATION);
/* destroy the association, i.e. free memory of T_ASC_Association* structure. This */
/* call is the counterpart of ASC_requestAssociation(...) which was called above. */
cond = ASC_destroyAssociation(&m_pAssoc);
if (cond.bad())
{
OFLOG_FATAL(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
CALLBACK_ERROR(m_pCallback, DESTROY_ASSOCIATION);
return listSendCompleteFile;
}
/* drop the network, i.e. free memory of T_ASC_Network* structure. This call */
/* is the counterpart of ASC_initializeNetwork(...) which was called above. */
CALLBACK_INFO(m_pCallback, DROP_NETWORK);
cond = ASC_dropNetwork(&m_pNetwork);
if (cond.bad())
{
OFLOG_FATAL(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
CALLBACK_INFO(m_pCallback, DROP_NETWORK);
return listSendCompleteFile;
}
OFLOG_FATAL(*m_pLoggerStoreSCU, "------------------------------------ End --------------------------------------------");
return listSendCompleteFile;
//SetSleep(10);
/*
SetSleep(10);
const char* pServerAETitle = NULL;
const char* pClientAETitle = NULL;
OFString strServerIPnPort;
char* pPeer = NULL;
OFBool bSecureConnection = false;
OFList<OFString> sopClassUIDList; // the list of SOP classes
OFList<OFString> sopInstanceUIDList; // the list of SOP instances
OFCondition cond;
int nLength = 0;
char sopClassUID[128];
char sopInstanceUID[128];
OFString temp_str;
//fileNameList.push_back("test.dcm");
OFListIterator(OFString) iterFirst = m_pCurrentFileNameList->begin();
OFString strFirstDcmFile = *iterFirst;
//FindSOPClassAndInstanceInFile("mpeg_test.dcm", sopClassUID, sopInstanceUID);
memset(sopClassUID, 0, 128);
memset(sopInstanceUID, 0, 128);
FindSOPClassAndInstanceInFile(strFirstDcmFile.c_str(), sopClassUID, sopInstanceUID);
pServerAETitle = m_strServerAETitle.c_str();
pClientAETitle = m_strAETitle.c_str();
m_nTimeoutACSE = 10;
m_pLoggerStoreSCU->ClearLog();
//DCM_dcmnetLogger = *m_pLoggerStoreSCU;
OFLOG_FATAL(*m_pLoggerStoreSCU, "------------------------ DICOM Store Start --------------------------------------------");
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 1, NULL);
Sleep(10);
cond = ASC_initializeNetwork(NET_REQUESTOR, 0, m_nTimeoutACSE, &m_pNetwork);
if (cond.bad())
{
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 1, NULL);
Sleep(10);
return;
}
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 2, NULL);
Sleep(10);
cond = ASC_createAssociationParameters(&m_pNetworkParams, m_nMaxReceivePDULength);
if (cond.bad())
{
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 2, NULL);
Sleep(10);
return;
}
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 3, NULL);
Sleep(10);
cond = ASC_setAPTitles(m_pNetworkParams, pClientAETitle, pServerAETitle, NULL);
if (cond.bad())
{
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 3, NULL);
Sleep(10);
return;
}
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 4, NULL);
Sleep(10);
cond = ASC_setTransportLayerType(m_pNetworkParams, bSecureConnection);
if (cond.bad())
{
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 4, NULL);
Sleep(10);
return;
}
gethostname(m_LocalHost, sizeof(m_LocalHost)-1);
// sprintf(peerHost, "%s:%d", pPeer, OFstatic_cast(int, m_nPort));
//sprintf(m_LocalHost, "192.168.123.23");
char* pStrServerIPnPort = new char[1024];
sprintf(pStrServerIPnPort, "%s:%d", m_strHostIP.c_str(), m_nPort);
strServerIPnPort = pStrServerIPnPort;
delete[] pStrServerIPnPort;
nLength = strServerIPnPort.length();
const char* pData = NULL;
pData = strServerIPnPort.c_str();
memset(m_PeerHost, 0, sizeof(m_PeerHost));
memcpy(m_PeerHost, pData, nLength);
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 5, NULL);
Sleep(10);
cond = ASC_setPresentationAddresses(m_pNetworkParams, m_LocalHost, m_PeerHost);
if (cond.bad())
{
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 5, NULL);
Sleep(10);
return;
}
sopClassUIDList.push_back(sopClassUID);
sopInstanceUIDList.push_back(sopInstanceUID);
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 6, NULL);
Sleep(10);
cond = AddStoragePresentationContexts(m_pNetworkParams, sopClassUIDList);
if (cond.bad())
{
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 6, NULL);
Sleep(10);
return;
}
dcmConnectionTimeout.set(5);
#include "dcmtk\dcmnet\dul.h"
m_pNetworkParams->DULparams.requestedPresentationContext;
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 7, NULL);
Sleep(10);
cond = ASC_requestAssociation(m_pNetwork, m_pNetworkParams, &m_pAssoc);
//cond = m_pNetClass->ASC_requestAssociation(m_pNetwork, m_pNetworkParams, &m_pAssoc);
if (cond.bad())
{
if (cond == DUL_ASSOCIATIONREJECTED)
{
T_ASC_RejectParameters rej;
ASC_getRejectParameters(m_pNetworkParams, &rej);
OFLOG_FATAL(*m_pLoggerStoreSCU, "Association Rejected:" << OFendl << ASC_printRejectParameters(temp_str, &rej));
}
else
{
OFLOG_FATAL(*m_pLoggerStoreSCU, "Association Rejected:" << OFendl << cond.text());
if(m_pAssoc!=NULL)
{
cond = ASC_destroyAssociation(&m_pAssoc);
}
if(m_pNetwork!=NULL)
{
cond = ASC_dropNetwork(&m_pNetwork);
}
}
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 7, NULL);
Sleep(10);
return;
}
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 8, NULL);
Sleep(10);
if (ASC_countAcceptedPresentationContexts(m_pNetworkParams) == 0)
{
OFLOG_FATAL(*m_pLoggerStoreSCU, "No Acceptable Presentation Contexts");
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 8, NULL);
Sleep(10);
return;
}
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND, 9, NULL);
Sleep(10);
cond = CheckUserIdentityResponse(m_pNetworkParams);
if (cond.bad())
{
OFLOG_FATAL(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 9, NULL);
Sleep(10);
return;
}
cond = EC_Normal;
OFListIterator(OFString) iter = m_pCurrentFileNameList->begin();
OFListIterator(OFString) enditer = m_pCurrentFileNameList->end();
if (iter != enditer)
{
while ((iter != enditer) && cond.good())
{
cond = cstore(m_pAssoc, *iter);
if (cond.good())
{
cond = EC_Normal;
m_bUnsuccessfulStoreEncountered = false;
}
++iter;
}
}
else
{
cond = cstore(m_pAssoc, *iter);
}
if (cond == EC_Normal)
{
if (m_bAbortAssociation == true)
{
OFLOG_INFO(*m_pLoggerStoreSCU, "Aborting Association");
cond = ASC_abortAssociation(m_pAssoc);
if (cond.bad())
{
OFLOG_ERROR(*m_pLoggerStoreSCU, "Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 10, NULL);
Sleep(10);
return;
}
}
else {
OFLOG_INFO(*m_pLoggerStoreSCU, "Releasing Association");
cond = ASC_releaseAssociation(m_pAssoc);
if (cond.bad())
{
OFLOG_ERROR(*m_pLoggerStoreSCU, "Association Release Failed: " << DimseCondition::dump(temp_str, cond));
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 11, NULL);
Sleep(10);
return;
}
}
}
else if (cond == DUL_PEERREQUESTEDRELEASE)
{
OFLOG_ERROR(*m_pLoggerStoreSCU, "Protocol Error: Peer requested release (Aborting)");
OFLOG_INFO(*m_pLoggerStoreSCU, "Aborting Association");
cond = ASC_abortAssociation(m_pAssoc);
if (cond.bad())
{
OFLOG_ERROR(*m_pLoggerStoreSCU, "Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 12, NULL);
Sleep(10);
return;
}
}
else if (cond == DUL_PEERABORTEDASSOCIATION)
{
OFLOG_INFO(*m_pLoggerStoreSCU, "Peer Aborted Association");
}
else
{
OFLOG_ERROR(*m_pLoggerStoreSCU, "Store SCU Failed: " << DimseCondition::dump(temp_str, cond));
OFLOG_INFO(*m_pLoggerStoreSCU, "Aborting Association");
cond = ASC_abortAssociation(m_pAssoc);
if (cond.bad())
{
OFLOG_ERROR(*m_pLoggerStoreSCU, "Association Abort Failed: " << DimseCondition::dump(temp_str, cond));
cond = ASC_destroyAssociation(&m_pAssoc);
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 13, NULL);
Sleep(10);
return;
}
}
cond = ASC_destroyAssociation(&m_pAssoc);
if (cond.bad())
{
OFLOG_FATAL(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 14, NULL);
Sleep(10);
return;
}
cond = ASC_dropNetwork(&m_pNetwork);
if (cond.bad())
{
OFLOG_FATAL(*m_pLoggerStoreSCU, DimseCondition::dump(temp_str, cond));
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_ERROR, 15, NULL);
Sleep(10);
return;
}
m_pCallbackThread->PostThreadMessage(WM_PROGRESS_SEND_COMPLETE, NULL, NULL);
Sleep(10);
OFLOG_FATAL(*m_pLoggerStoreSCU, "------------------------------------ End --------------------------------------------");
SetSleep(1);
*/
}
void CSDCMSendImpl::SetLogLevel(int nLevel)
{
//m_pLoggerStoreSCU->SetLogLevel((OFLogger::LogLevel)nLevel);
}
OFLogger* CSDCMSendImpl::GetLogger()
{
return m_pLoggerStoreSCU;
}