#include "SDCMSendImpl.h" //#include "SThreadProgress.h" #include #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 #include #include #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 &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 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 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 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 &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 &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 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 CSDCMSendImpl::OnDCMSend() { vector listSendCompleteFile; //SetSleep(10); const char* pServerAETitle = NULL; const char* pClientAETitle = NULL; OFString strServerIPnPort; // char* pPeer = NULL; OFBool bSecureConnection = false; OFList sopClassUIDList; // the list of SOP classes OFList 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 sopClassUIDList; // the list of SOP classes OFList 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; }