OFCondition Association::Drop(OFCondition cond) { // tear down association if(cond == EC_Normal) { /* release association */ cond = ASC_releaseAssociation(assoc); } else if(cond == DUL_PEERREQUESTEDRELEASE) { cond = ASC_abortAssociation(assoc); if (cond.good()) { return cond; } } else if(cond == DUL_PEERABORTEDASSOCIATION) { return cond; } else { cond = ASC_abortAssociation(assoc); if (cond.good()) { return cond; } } Destroy(); return cond; }
void Association ::abort() { if(!this->is_associated()) { throw Exception("Not associated"); } ASC_abortAssociation(this->_association); ASC_destroyAssociation(&this->_association); this->_association = NULL; }
bool CommandDispatcher::Step() /* * This function receives DIMSE commmands over the network connection * and handles these commands correspondingly. Note that in case of * storscp only C-ECHO-RQ and C-STORE-RQ commands can be processed. */ { bool finished = false; // receive a DIMSE command over the network, with a timeout of 1 second DcmDataset *statusDetail = NULL; T_ASC_PresentationContextID presID = 0; T_DIMSE_Message msg; OFCondition cond = DIMSE_receiveCommand(assoc_, DIMSE_NONBLOCKING, 1, &presID, &msg, &statusDetail); elapsedTimeSinceLastCommand_++; // if the command which was received has extra status // detail information, dump this information if (statusDetail != NULL) { //LOG4CPP_WARN(Internals::GetLogger(), "Status Detail:" << OFendl << DcmObject::PrintHelper(*statusDetail)); delete statusDetail; } if (cond == DIMSE_OUTOFRESOURCES) { finished = true; } else if (cond == DIMSE_NODATAAVAILABLE) { // Timeout due to DIMSE_NONBLOCKING if (clientTimeout_ != 0 && elapsedTimeSinceLastCommand_ >= clientTimeout_) { // This timeout is actually a client timeout finished = true; } } else if (cond == EC_Normal) { // Reset the client timeout counter elapsedTimeSinceLastCommand_ = 0; // in case we received a valid message, process this command // note that storescp can only process a C-ECHO-RQ and a C-STORE-RQ switch (msg.CommandField) { case DIMSE_C_ECHO_RQ: // process C-ECHO-Request cond = EchoScp(assoc_, &msg, presID); break; case DIMSE_C_STORE_RQ: // process C-STORE-Request if (server_.HasStoreRequestHandlerFactory()) { std::auto_ptr<IStoreRequestHandler> handler (server_.GetStoreRequestHandlerFactory().ConstructStoreRequestHandler()); cond = Internals::storeScp(assoc_, &msg, presID, *handler); } else cond = DIMSE_BADCOMMANDTYPE; // Should never happen break; case DIMSE_C_MOVE_RQ: // process C-MOVE-Request if (server_.HasMoveRequestHandlerFactory()) { std::auto_ptr<IMoveRequestHandler> handler (server_.GetMoveRequestHandlerFactory().ConstructMoveRequestHandler()); cond = Internals::moveScp(assoc_, &msg, presID, *handler); } else cond = DIMSE_BADCOMMANDTYPE; // Should never happen break; case DIMSE_C_FIND_RQ: // process C-FIND-Request if (server_.HasFindRequestHandlerFactory()) { std::auto_ptr<IFindRequestHandler> handler (server_.GetFindRequestHandlerFactory().ConstructFindRequestHandler()); cond = Internals::findScp(assoc_, &msg, presID, *handler); } else cond = DIMSE_BADCOMMANDTYPE; // Should never happen break; default: // we cannot handle this kind of message cond = DIMSE_BADCOMMANDTYPE; LOG(ERROR) << "cannot handle command: 0x" << std::hex << msg.CommandField; break; } } else { // Bad status, which indicates the closing of the connection by // the peer or a network error finished = true; } if (finished) { if (cond == DUL_PEERREQUESTEDRELEASE) { LOG(INFO) << "Association Release"; ASC_acknowledgeRelease(assoc_); } else if (cond == DUL_PEERABORTEDASSOCIATION) { LOG(INFO) << "Association Aborted"; } else { OFString temp_str; LOG(ERROR) << "DIMSE failure (aborting association): " << cond.text(); /* some kind of error so abort the association */ ASC_abortAssociation(assoc_); } } return !finished; }
OFCondition RetrieveDICOMFilesFromPACS::subOperationSCP(T_ASC_Association **subAssociation) { // Ens convertim com en un servei. El PACS ens fa peticions que nosaltres hem de respondre, ens pot demanar descarregar una imatge o fer un echo T_DIMSE_Message dimseMessage; T_ASC_PresentationContextID presentationContextID; if (!ASC_dataWaiting(*subAssociation, 0)) { return DIMSE_NODATAAVAILABLE; } OFCondition condition = DIMSE_receiveCommand(*subAssociation, DIMSE_BLOCKING, 0, &presentationContextID, &dimseMessage, NULL); if (condition == EC_Normal) { switch (dimseMessage.CommandField) { case DIMSE_C_STORE_RQ: condition = storeSCP(*subAssociation, &dimseMessage, presentationContextID); break; case DIMSE_C_ECHO_RQ: condition = echoSCP(*subAssociation, &dimseMessage, presentationContextID); break; default: ERROR_LOG("El PACS ens ha sol.licitat un tipus d'operacio invalida"); condition = DIMSE_BADCOMMANDTYPE; break; } } // Clean up on association termination if (condition == DUL_PEERREQUESTEDRELEASE) { INFO_LOG("El PACS sol.licita tancar la connexio per on ens ha enviat els fitxers"); condition = ASC_acknowledgeRelease(*subAssociation); ASC_dropSCPAssociation(*subAssociation); ASC_destroyAssociation(subAssociation); return condition; } else if (condition == DUL_PEERABORTEDASSOCIATION) { INFO_LOG("El PACS ha abortat la connexió"); } else if (condition != EC_Normal) { ERROR_LOG("S'ha produit un error reben la peticio d'una suboperacio, descripcio error: " + QString(condition.text())); condition = ASC_abortAssociation(*subAssociation); } else if (m_abortIsRequested) { INFO_LOG("Abortarem les connexions amb el PACS, perque han sol.licitant cancel.lar la descarrega"); condition = ASC_abortAssociation(*subAssociation); if (!condition.good()) { ERROR_LOG("Error al abortar la connexio pel qual rebem les imatges" + QString(condition.text())); } // Tanquem la connexió amb el PACS perquè segons indica la documentació DICOM al PS 3.4 (Baseline Behavior of SCP) C.4.2.3.1 si abortem // la connexió per la qual rebem les imatges, el comportament del PACS és desconegut, per exemple DCM4CHEE tanca la connexió amb el PACS, però // el RAIM_Server no la tanca i la manté fent que no sortim mai d'aquesta classe. Degut a que no es pot saber en aquesta situació com actuaran // els PACS es tanca aquí la connexió amb el PACS. condition = ASC_abortAssociation(m_pacsConnection->getConnection()); if (!condition.good()) { ERROR_LOG("Error al abortar la connexio pel amb el PACS" + QString(condition.text())); } else { INFO_LOG("Abortada la connexio amb el PACS"); } } if (condition != EC_Normal) { ASC_dropAssociation(*subAssociation); ASC_destroyAssociation(subAssociation); } return condition; }
bool echoscu(const QString &peerTitle, const QString &ourTitle, const QString &hostname, int port, QString &msg) { T_ASC_Network *net; T_ASC_Parameters *params; T_ASC_Association *assoc; OFString temp_str; bool ret = false; #ifdef HAVE_WINSOCK_H WSAData winSockData; /* we need at least version 1.1 */ WORD winSockVersionNeeded = MAKEWORD( 1, 1 ); WSAStartup(winSockVersionNeeded, &winSockData); #endif /* initialize network, i.e. create an instance of T_ASC_Network*. */ OFCondition cond = ASC_initializeNetwork(NET_REQUESTOR, 0, 6, &net); if (cond.bad()) { DimseCondition::dump(temp_str, cond); msg = QString::fromLatin1(temp_str.c_str()); goto cleanup; } /* initialize asscociation parameters, i.e. create an instance of T_ASC_Parameters*. */ cond = ASC_createAssociationParameters(¶ms, ASC_DEFAULTMAXPDU); if (cond.bad()) { DimseCondition::dump(temp_str, cond); msg = QString::fromLatin1(temp_str.c_str()); goto cleanup; } ASC_setAPTitles(params, ourTitle.toLocal8Bit().data(), peerTitle.toLocal8Bit().data(), NULL); /* Set the transport layer type (type of network connection) in the params */ /* strucutre. The default is an insecure connection; where OpenSSL is */ /* available the user is able to request an encrypted,secure connection. */ cond = ASC_setTransportLayerType(params, OFFalse); if (cond.bad()) { DimseCondition::dump(temp_str, cond); msg = QString::fromLatin1(temp_str.c_str()); goto cleanup; } /* Figure out the presentation addresses and copy the */ /* corresponding values into the association parameters.*/ DIC_NODENAME localHost; DIC_NODENAME peerHost; gethostname(localHost, sizeof(localHost) - 1); sprintf(peerHost, "%s:%d", hostname.toLocal8Bit().data(), port); ASC_setPresentationAddresses(params, localHost, peerHost); /* Set the presentation contexts which will be negotiated */ /* when the network connection will be established */ int presentationContextID = 1; /* odd byte value 1, 3, 5, .. 255 */ for (unsigned long ii=0; ii<1; ii++) { cond = ASC_addPresentationContext(params, presentationContextID, UID_VerificationSOPClass, transferSyntaxes, 3); presentationContextID += 2; if (cond.bad()) { DimseCondition::dump(temp_str, cond); msg = QString::fromLatin1(temp_str.c_str()); goto cleanup; } } /* create association, i.e. try to establish a network connection to another */ /* DICOM application. This call creates an instance of T_ASC_Association*. */ cond = ASC_requestAssociation(net, params, &assoc); if (cond.bad()) { if (cond == DUL_ASSOCIATIONREJECTED) { T_ASC_RejectParameters rej; ASC_getRejectParameters(params, &rej); ASC_printRejectParameters(temp_str, &rej); msg = QString("Association Rejected: %1").arg(temp_str.c_str()); goto cleanup; } else { DimseCondition::dump(temp_str, cond); msg = QString("Association Request Failed: %1").arg(temp_str.c_str()); goto cleanup; } } /* count the presentation contexts which have been accepted by the SCP */ /* If there are none, finish the execution */ if (ASC_countAcceptedPresentationContexts(params) == 0) { msg = QString("No Acceptable Presentation Contexts"); goto cleanup; } /* do the real work, i.e. send a number of C-ECHO-RQ messages to the DICOM application */ /* this application is connected with and handle corresponding C-ECHO-RSP messages. */ DIC_US msgId = assoc->nextMsgID++; DIC_US status; DcmDataset *statusDetail = NULL; /* send C-ECHO-RQ and handle response */ cond = DIMSE_echoUser(assoc, msgId, DIMSE_BLOCKING, 0, &status, &statusDetail); /* check for status detail information, there should never be any */ if (statusDetail != NULL) { delete statusDetail; } /* tear down association, i.e. terminate network connection to SCP */ if (cond == EC_Normal) { cond = ASC_releaseAssociation(assoc); ret = true; } else if (cond == DUL_PEERABORTEDASSOCIATION) { } else { DimseCondition::dump(temp_str, cond); msg = QString::fromLatin1(temp_str.c_str()); cond = ASC_abortAssociation(assoc); } cleanup: /* 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(&assoc); /* drop the network, i.e. free memory of T_ASC_Network* structure. This call */ /* is the counterpart of ASC_initializeNetwork(...) which was called above. */ cond = ASC_dropNetwork(&net); #ifdef HAVE_WINSOCK_H WSACleanup(); #endif return ret; }