1875 lines
61 KiB
C++
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;
|
|
}
|