Files
DCMV/thirdparty/dcm_network/dcm_store.cpp
2022-07-08 10:04:23 +08:00

820 lines
22 KiB
C++

#include "dcm_store.h"
//----------------------------------------------------------------------------------------------------
// dcm_cstore_callback
dcm_cstore_callback::dcm_cstore_callback()
{
}
dcm_cstore_callback::~dcm_cstore_callback()
{
}
////dcm_cstore_callback::dcm_cstore_callback(const dcm_cstore_callback& other)
////{
////}
////
////dcm_cstore_callback& dcm_cstore_callback::operator=(const dcm_cstore_callback& other)
////{
////}
//---------------------------------------------------------------------------------------------------------
// static function
static void progressCallback(void *callbackData, T_DIMSE_StoreProgress *progress, T_DIMSE_C_StoreRQ *request)
{
dcm_cstore_callback *callback = reinterpret_cast<dcm_cstore_callback *>(callbackData);
if (callback)
callback->callback(progress, request);
}
//---------------------------------------------------------------------------------------------------------
// dcm-cstore
dcm_cstore::dcm_cstore(const char *peerIp, unsigned long peerPort, const char *peerTitle, const char *ourTitle)
: abortAssociation(false)
, maxReceivedPDULength(ASC_DEFAULTMAXPDU)
, maxSendPDULength(ASC_DEFAULTMAXPDU)
, networkTransferSyntax(EXS_Unknown)
, readMode(ERM_autoDetect)
, scanDir(true)
, recurse(true)
, scanPattern("")
, haltOnUnsuccessfulStore(true)
, unsuccessfulStoreEncountered(false)
, lastStatusCode(STATUS_Success)
, proposeOnlyRequiredPresentationContexts(false)
, combineProposedTransferSyntaxes(false)
, repeatCount(1)
, inventPatientCount(25)
, inventStudyCount(50)
, inventSeriesCount(100)
, inventSOPInstanceInformation(false)
, correctUIDPadding(false)
, patientNamePrefix("OFFIS^TEST_PN_")
, patientIDPrefix("PID_")
, studyIDPrefix("SID_")
, accessionNumberPrefix("")
, configFile(NULL)
, profileName(NULL)
, blockMode(DIMSE_BLOCKING)
, dimse_tiemout(0)
, acse_tiemout(30)
, socket_tiemout(60)
, identMode(ASC_USER_IDENTITY_NONE)
, user("")
, password("")
, identFile_("")
, identResponse(false)
, cstore_callback(nullptr)
, patientCounter(0)
, studyCounter(0)
, seriesCounter(0)
, imageCounter(0)
{
peerIp_ = peerIp;
peerPort_ = peerPort;
peerTitle_ = peerTitle;
ourTitle_ = ourTitle;
}
dcm_cstore::~dcm_cstore()
{
}
void dcm_cstore::set_dimse_tiemout(int timeout)
{
dimse_tiemout = timeout;
}
void dcm_cstore::set_acse_tiemout(int timeout)
{
acse_tiemout = timeout;
}
void dcm_cstore::set_ma_received_pdu_length(unsigned long length)
{
maxReceivedPDULength = length;
}
void dcm_cstore::set_max_send_pdu_length(unsigned long length)
{
maxSendPDULength = length;
}
void dcm_cstore::set_store_callback(dcm_cstore_callback *callback)
{
cstore_callback = callback;
}
int dcm_cstore::secondsSince1970()
{
time_t t = time(NULL);
return static_cast<int>(t);
}
std::string dcm_cstore::intToString(int i)
{
char numbuf[32];
sprintf(numbuf, "%d", i);
return numbuf;
}
std::string dcm_cstore::makeUID(std::string basePrefix, int counter)
{
std::string prefix = basePrefix + "." + intToString(counter);
char uidbuf[65];
std::string uid = dcmGenerateUniqueIdentifier(uidbuf, prefix.c_str());
return uid;
}
bool dcm_cstore::updateStringAttributeValue(DcmItem *dataset, const DcmTagKey &key, std::string &value)
{
DcmStack stack;
DcmTag tag(key);
OFCondition cond = EC_Normal;
cond = dataset->search(key, stack, ESM_fromHere, false);
if (cond != EC_Normal)
{
// log >> "updateStringAttributeValue : cannot find
return false;
}
DcmElement *elem = static_cast<DcmElement *>(stack.top());
DcmVR vr(elem->ident());
if (elem->getLength() > vr.getMaxValueLength())
{
// log >> undateStringAttributeValue : INTERNAL ERROR
return false;
}
cond = elem->putOFStringArray(value);
if (cond != EC_Normal)
{
// log >> updateStringAttributeValue : cannot put string in attribute
return false;
}
return true;
}
void dcm_cstore::replaceSOPInstanceInformation(DcmDataset *dataset)
{
std::string seriesInstanceUID;
std::string seriesNumber;
std::string studyInstanceUID;
std::string studyID;
std::string accessionNumber;
std::string patientID;
std::string patientName;
if (seriesInstanceUID.empty())
seriesInstanceUID = makeUID(SITE_SERIES_UID_ROOT, static_cast<int>(seriesCounter));
if (seriesNumber.empty())
seriesNumber = intToString(static_cast<int>(seriesCounter));
if (studyInstanceUID.empty())
studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, static_cast<int>(studyCounter));
if (studyID.empty())
studyID = studyIDPrefix + intToString(static_cast<int>(secondsSince1970())) + intToString(static_cast<int>(studyCounter));
if (accessionNumber.empty())
accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString(static_cast<int>(studyCounter));
if (patientID.empty())
patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString(static_cast<int>(patientCounter));
if (patientName.empty())
patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString(static_cast<int>(patientCounter));
if (imageCounter >= inventSeriesCount)
{
imageCounter = 0;
seriesCounter++;
seriesInstanceUID = makeUID(SITE_SERIES_UID_ROOT, static_cast<int>(seriesCounter));
seriesNumber = intToString(static_cast<int>(seriesCounter));
}
if (seriesCounter >= inventStudyCount)
{
seriesCounter = 0;
studyCounter++;
studyInstanceUID = makeUID(SITE_STUDY_UID_ROOT, static_cast<int>(studyCounter));
studyID = studyIDPrefix + intToString(secondsSince1970()) + intToString(static_cast<int>(studyCounter));
accessionNumber = accessionNumberPrefix + intToString(secondsSince1970()) + intToString(static_cast<int>(studyCounter));
}
if (studyCounter >= inventPatientCount)
{
studyCounter = 0;
patientCounter++;
patientID = patientIDPrefix + intToString(secondsSince1970()) + intToString(static_cast<int>(patientCounter));
patientName = patientNamePrefix + intToString(secondsSince1970()) + intToString(static_cast<int>(patientCounter));
}
std::string sopInstanceUID = makeUID(SITE_INSTANCE_UID_ROOT, static_cast<int>(imageCounter));
std::string imageNumber = intToString(static_cast<int>(imageCounter));
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++;
}
OFCondition dcm_cstore::addStoragePresentationContexts(T_ASC_Parameters *params, std::list<std::string> &sopClasses)
{
std::string preferredTransferSyntax;
if (networkTransferSyntax == EXS_Unknown)
{
if (gLocalByteOrder == E_ByteOrder::EBO_LittleEndian)
{
preferredTransferSyntax = UID_LittleEndianExplicitTransferSyntax;
}
else
{
preferredTransferSyntax = UID_BigEndianExplicitTransferSyntax;
}
}
else
{
DcmXfer xfer(networkTransferSyntax);
preferredTransferSyntax = xfer.getXferID();
}
std::list<std::string>::iterator s_cur;
std::list<std::string>::iterator s_end;
std::list<std::string> fallbackSyntaxes;
if ((networkTransferSyntax != EXS_LittleEndianImplicit) &&
(networkTransferSyntax != EXS_MPEG2MainProfileAtMainLevel) &&
(networkTransferSyntax != EXS_MPEG2MainProfileAtHighLevel) &&
(networkTransferSyntax != EXS_MPEG4HighProfileLevel4_1) &&
(networkTransferSyntax != EXS_MPEG4BDcompatibleHighProfileLevel4_1) &&
(networkTransferSyntax != EXS_MPEG4HighProfileLevel4_2_For2DVideo) &&
(networkTransferSyntax != EXS_MPEG4HighProfileLevel4_2_For3DVideo) &&
(networkTransferSyntax != EXS_MPEG4StereoHighProfileLevel4_2) &&
(networkTransferSyntax != EXS_HEVCMainProfileLevel5_1) &&
(networkTransferSyntax != EXS_HEVCMain10ProfileLevel5_1))
{
fallbackSyntaxes.push_back(UID_LittleEndianExplicitTransferSyntax);
fallbackSyntaxes.push_back(UID_BigEndianExplicitTransferSyntax);
fallbackSyntaxes.push_back(UID_LittleEndianImplicitTransferSyntax);
fallbackSyntaxes.remove(preferredTransferSyntax);
}
std::list<std::string> combinedSyntaxes;
s_cur = fallbackSyntaxes.begin();
s_end = fallbackSyntaxes.end();
combinedSyntaxes.push_back(preferredTransferSyntax);
while (s_cur != s_end)
{
if (!isaListMember(combinedSyntaxes, *s_cur))
{
combinedSyntaxes.push_back(*s_cur);
}
++s_cur;
}
if (!proposeOnlyRequiredPresentationContexts)
{
for (int i = 0; i < numberOfDcmShortSCUStorageSOPClassUIDs; i++)
{
sopClasses.push_back(dcmShortSCUStorageSOPClassUIDs[i]);
}
}
std::list<std::string> sops;
s_cur = sopClasses.begin();
s_end = sopClasses.end();
while (s_cur != s_end)
{
if (!isaListMember(sops, *s_cur))
{
sops.push_back(*s_cur);
}
++s_cur;
}
OFCondition cond = EC_Normal;
int pid = 1;
s_cur = sops.begin();
s_end = sops.end();
while (s_cur != s_end && cond.good())
{
if (pid > 255)
{
// log >> Too many presentation contexts
return ASC_BADPRESENTATIONCONTEXTID;
}
if (combineProposedTransferSyntaxes)
{
addPresentationContext(params, pid, *s_cur, combinedSyntaxes);
pid += 2;
}
else
{
cond = addPresentationContext(params, pid, *s_cur, preferredTransferSyntax);
pid += 2;
if (fallbackSyntaxes.size() > 0)
{
if (pid > 255)
{
// log >> Too many presentation contexes
return ASC_BADPRESENTATIONCONTEXTID;
}
cond = addPresentationContext(params, pid, *s_cur, fallbackSyntaxes);
pid += 2;
}
}
++s_cur;
}
return cond;
}
bool dcm_cstore::findSOPClassAndInstanceInFile(const char *fname, char *sopClass, size_t sopClassSize, char *sopInstance, size_t sopInstanceSize)
{
DcmFileFormat ff;
if (!ff.loadFile(fname, EXS_Unknown, EGL_noChange, DCM_MaxReadLength, readMode).good())
{
return false;
}
bool found = DU_findSOPClassAndInstanceInDataSet(ff.getMetaInfo(), sopClass, sopClassSize, sopInstance, sopInstanceSize, correctUIDPadding);
if (!found)
found = DU_findSOPClassAndInstanceInDataSet(ff.getDataset(), sopClass, sopClassSize, sopInstance, sopInstanceSize, correctUIDPadding);
return found;
}
OFCondition dcm_cstore::configureUserIdentityRequest(T_ASC_Parameters *params)
{
OFCondition cond = EC_Normal;
switch (identMode)
{
case ASC_USER_IDENTITY_USER:
{
cond = ASC_setIdentRQUserOnly(params, user, identResponse);
break;
}
case ASC_USER_IDENTITY_USER_PASSWORD:
{
cond = ASC_setIdentRQUserPassword(params, user, password, identResponse);
break;
}
case ASC_USER_IDENTITY_KERBEROS:
case ASC_USER_IDENTITY_SAML:
case ASC_USER_IDENTITY_JWT:
{
OFFile identFile;
if (!identFile.fopen(identFile_.c_str(), "rb"))
{
// log >> Unable to open Kerberbose, SAML or JWT file
return EC_IllegalCall;
}
offile_off_t result = identFile.fseek(0, SEEK_END);
if (result != 0)
return EC_IllegalParameter;
offile_off_t filesize = identFile.ftell();
if (filesize > 65535)
{
// log >> "Kerberos, SAML or JWT file is larger than 65535 bytes, bytes after that position are ignored
filesize = 65535;
}
char *buf = new char[static_cast<unsigned int>(filesize)];
size_t bytesRead = identFile.fread(buf, 1, static_cast<size_t>(filesize));
identFile.fclose();
if (bytesRead == 0)
{
// log >> Unable to read Kerberos, SAML or JWT info file
delete[] buf;
return EC_IllegalCall;
}
if (identMode == ASC_USER_IDENTITY_KERBEROS)
cond = ASC_setIdentRQKerberos(params, buf, static_cast<Uint16>(bytesRead), identResponse);
else if (identMode == ASC_USER_IDENTITY_SAML)
cond = ASC_setIdentRQSaml(params, buf, static_cast<Uint16>(bytesRead), identResponse);
else
cond = ASC_setIdentRQJwt(params, buf, static_cast<Uint16>(bytesRead), identResponse);
delete[] buf;
break;
}
default:
{
cond = EC_IllegalCall;
break;
}
}
if (cond.bad())
{
// log >> Failed
}
return cond;
}
OFCondition dcm_cstore::checkUserIdentityResponse(T_ASC_Parameters *params)
{
if (params == NULL)
return ASC_NULLKEY;
if (identMode == ASC_USER_IDENTITY_NONE || !identResponse)
return EC_Normal;
if (identMode == ASC_USER_IDENTITY_USER || identMode == ASC_USER_IDENTITY_USER_PASSWORD)
{
UserIdentityNegotiationSubItemAC *rsp = params->DULparams.ackUserIdentNeg;
if (rsp == NULL)
{
// log >> User Identity Negotitation failed: Positive response requested but none received
return ASC_USERIDENTIFICATIONFAILED;
}
}
return EC_Normal;
}
bool dcm_cstore::isaListMember(std::list<std::string> &lst, std::string &s)
{
std::list<std::string>::iterator cur = lst.begin();
std::list<std::string>::iterator end = lst.end();
bool found = false;
while (cur != end && !found)
{
found = (s == *cur);
++cur;
}
return found;
}
OFCondition dcm_cstore::addPresentationContext(T_ASC_Parameters *params, int presentationContextId, const std::string &abstractSyntax, const std::string &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 dcm_cstore::addPresentationContext(T_ASC_Parameters *params, int presentationContextId, const std::string &abstracySyntax, const std::list<std::string> &transferSyntaxList, T_ASC_SC_ROLE proposedRole)
{
const char **transferSyntaxes = new const char*[transferSyntaxList.size()];
int transferSyntaxCount = 0;
std::list<std::string>::const_iterator s_cur = transferSyntaxList.begin();
std::list<std::string>::const_iterator s_end = transferSyntaxList.end();
while (s_cur != s_end)
{
transferSyntaxes[transferSyntaxCount++] = (*s_cur).c_str();
++s_cur;
}
OFCondition cond = ASC_addPresentationContext(params, presentationContextId, abstracySyntax.c_str(), transferSyntaxes, transferSyntaxCount, proposedRole);
delete[] transferSyntaxes;
return cond;
}
OFCondition dcm_cstore::storeSCU(T_ASC_Association *assoc, const char *fname)
{
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;
unsuccessfulStoreEncountered = true;
DcmFileFormat dcmff;
OFCondition cond = dcmff.loadFile(fname, EXS_Unknown, EGL_noChange, DCM_MaxReadLength, readMode);
if (cond.bad())
{
// log >> Bad DICOM file
return cond;
}
if (inventSOPInstanceInformation)
{
replaceSOPInstanceInformation(dcmff.getDataset());
}
if (!DU_findSOPClassAndInstanceInDataSet(dcmff.getDataset(), sopClass, sizeof(sopClass), sopInstance, sizeof(sopInstance), correctUIDPadding))
{
// log >> No SOP Class or Instance UID in file
return DIMSE_BADDATA;
}
DcmXfer filexfer(dcmff.getDataset()->getOriginalXfer());
if (filexfer.isNotEncapsulated() && networkTransferSyntax == EXS_DeflatedLittleEndianExplicit)
{
filexfer = EXS_DeflatedLittleEndianExplicit;
}
if (filexfer.getXfer() != EXS_Unknown)
{
presID = ASC_findAcceptedPresentationContextID(assoc, sopClass, filexfer.getXferID());
}
else
{
presID = ASC_findAcceptedPresentationContextID(assoc, sopClass);
}
if (presID == 0)
{
const char *modalityName = dcmSOPClassUIDToModality(sopClass);
if (!modalityName)
modalityName = dcmFindNameOfUID(sopClass);
if (!modalityName)
modalityName = "unknown SOP class";
// log >> No presentation context for :
return DIMSE_NOVALIDPRESENTATIONCONTEXTID;
}
T_ASC_PresentationContext pc;
ASC_findAcceptedPresentationContext(assoc->params, presID, &pc);
DcmXfer netTransfer(pc.acceptedTransferSyntax);
bzero(reinterpret_cast<char *>(&req), sizeof(req));
req.MessageID = msgId;
OFStandard::strlcpy(req.AffectedSOPClassUID, sopClass, sizeof(req.AffectedSOPClassUID));
OFStandard::strlcpy(req.AffectedSOPInstanceUID, sopInstance, sizeof(req.AffectedSOPInstanceUID));
req.DataSetType = DIMSE_DATASET_PRESENT;
req.Priority = DIMSE_PRIORITY_MEDIUM;
cond = DIMSE_storeUser(assoc, presID, &req, NULL, dcmff.getDataset(), progressCallback, cstore_callback, blockMode, dimse_tiemout, &rsp, &statusDetail, NULL, static_cast<long>(OFStandard::getFileSize(fname)));
if (cond == EC_Normal && (rsp.DimseStatus == STATUS_Success || DICOM_WARNING_STATUS(rsp.DimseStatus)))
{
unsuccessfulStoreEncountered = false;
}
lastStatusCode = rsp.DimseStatus;
if (cond == EC_Normal)
{
// log >> Recevied Store Response
}
else
{
// log >> Store Failed, file
}
return cond;
}
OFCondition dcm_cstore::cstore(T_ASC_Association *assoc, const std::string &fname)
{
OFCondition cond = EC_Normal;
int n = static_cast<int>(repeatCount);
while (cond.good() && n-- && !(haltOnUnsuccessfulStore && unsuccessfulStoreEncountered))
{
cond = storeSCU(assoc, fname.c_str());
}
if (!haltOnUnsuccessfulStore)
{
cond = EC_Normal;
}
return cond;
}
int dcm_cstore::docstore(std::string dir)
{
std::list<std::string> fileNameList;
std::list<std::string> sopClassUIDList;
std::list<std::string> sopInstanceUIDList;
T_ASC_Network * net;
T_ASC_Parameters * params;
DIC_NODENAME peerHost;
T_ASC_Association * assoc;
DcmAssociationConfiguration asccfg;
OFStandard::initializeNetwork();
if (!dcmDataDict.isDictionaryLoaded())
{
// log >> "no data dictionary loaded, check environment variable
}
std::list<std::string> inputFiles;
OFStandard::searchDirectoryRecursively(dir.c_str(), inputFiles, scanPattern, "", recurse);
if (inputFiles.empty())
{
return e_no_input_file;
}
DcmFileFormat dfile;
char sopClassUID[128];
char sopInstanceUID[128];
bool ignoreName;
const char * currentFileName = NULL;
std::list<std::string>::iterator if_iter = inputFiles.begin();
std::list<std::string>::iterator if_last = inputFiles.end();
while (if_iter != if_last)
{
ignoreName = false;
currentFileName = (*if_iter).c_str();
if (OFStandard::fileExists(currentFileName))
{
if (proposeOnlyRequiredPresentationContexts)
{
if (!findSOPClassAndInstanceInFile(currentFileName, sopClassUID, sizeof(sopClassUID), sopInstanceUID, sizeof(sopInstanceUID)))
{
ignoreName = true;
if (haltOnUnsuccessfulStore)
{
// missing SOP class (or instance) in file
return e_no_presentation_context;
}
}
else if (!dcmIsaStorageSOPClassUID(sopClassUID, ESSC_All))
{
ignoreName = true;
if (haltOnUnsuccessfulStore)
{
// unknown storage SOP class in file
return e_unknown_storage_sopclass;
}
}
else
{
sopClassUIDList.push_back(sopClassUID);
sopInstanceUIDList.push_back(sopInstanceUID);
}
}
if (!ignoreName)
{
fileNameList.push_back(currentFileName);
}
}
else
{
if (haltOnUnsuccessfulStore)
{
// cannot access file
return e_cannot_access_file;
}
}
++if_iter;
}
OFCondition cond = ASC_initializeNetwork(NET_REQUESTOR, 0, acse_tiemout, &net);
if (cond.bad())
{
// log >> ASC_initializeNetwork Failed
return cond.code();
}
cond = ASC_createAssociationParameters(&params, maxReceivedPDULength);
if (cond.bad())
{
// log >> ASC_createAssociationParameters Failed
return cond.code();
}
ASC_setAPTitles(params, ourTitle_, peerTitle_, NULL);
sprintf(peerHost, "%s:%d", peerIp_, static_cast<int>(peerPort_));
ASC_setPresentationAddresses(params, OFStandard::getHostName().c_str(), peerHost);
if (identMode != ASC_USER_IDENTITY_NONE)
{
cond = configureUserIdentityRequest(params);
if (cond.bad())
return cond.code();
}
if (profileName)
{
std::string sprofile;
const unsigned char * c = reinterpret_cast<const unsigned char *>(profileName);
while (*c)
{
if (!isspace(*c))
sprofile += static_cast<char>(toupper(*c));
++c;
}
cond = asccfg.setAssociationParameters(sprofile.c_str(), *params);
}
else
{
cond = addStoragePresentationContexts(params, sopClassUIDList);
}
if (cond.bad())
{
// log >> addStoragePresentationContexts List Failed
return cond.code();
}
cond = ASC_requestAssociation(net, params, &assoc);
if (cond.bad())
{
if (cond == DUL_ASSOCIATIONREJECTED)
{
// Association Rejected
return cond.code();
}
else
{
// C-Store Association Request Failed
return cond.code();
}
}
if (ASC_countAcceptedPresentationContexts(params) == 0)
{
// No Acceptable Presentation Contexts
return e_no_acceptable_presentation_context;
}
cond = checkUserIdentityResponse(params);
if (cond.bad())
{
// checkUserIdentityResponse Failed
return cond.code();
}
// Association Accepted
cond = EC_Normal;
std::list<std::string>::iterator iter = fileNameList.begin();
std::list<std::string>::iterator enditer = fileNameList.end();
while (iter != enditer && cond.good())
{
cond = cstore(assoc, *iter);
++iter;
}
if (cond == EC_Normal)
{
if (abortAssociation)
{
// Aborting Association
cond = ASC_abortAssociation(assoc);
if (cond.bad())
{
// Association Abort Failed
return cond.code();
}
else
{
// Releasing Association
cond = ASC_releaseAssociation(assoc);
if (cond.bad())
{
// Association Release Failed
return cond.code();
}
}
}
}
else if (cond == DUL_PEERREQUESTEDRELEASE)
{
// Protocol Error: Peer request release
cond = ASC_abortAssociation(assoc);
if (cond.bad())
{
// Association Abort Failed
return cond.code();
}
}
else if (cond == DUL_PEERABORTEDASSOCIATION)
{
// Peer Aborted Association
}
else
{
// Store SCU Failed
cond = ASC_abortAssociation(assoc);
if (cond.bad())
{
// Association Abort Failed
return cond.code();
}
}
cond = ASC_destroyAssociation(&assoc);
if (cond.bad())
{
// ASC_destroyAssociation Failed
return cond.code();
}
cond = ASC_dropNetwork(&net);
if (cond.bad())
{
// ASC_dropNetwork Failed
return cond.code();
}
OFStandard::shutdownNetwork();
return e_ok;
}