CommandDispatcher* AcceptAssociation(const DicomServer& server, T_ASC_Network *net) { DcmAssociationConfiguration asccfg; char buf[BUFSIZ]; T_ASC_Association *assoc; OFCondition cond; OFString sprofile; OFString temp_str; std::vector<const char*> knownAbstractSyntaxes; // For C-STORE if (server.HasStoreRequestHandlerFactory()) { knownAbstractSyntaxes.push_back(UID_VerificationSOPClass); } // For C-FIND if (server.HasFindRequestHandlerFactory()) { knownAbstractSyntaxes.push_back(UID_FINDPatientRootQueryRetrieveInformationModel); knownAbstractSyntaxes.push_back(UID_FINDStudyRootQueryRetrieveInformationModel); } // For C-MOVE if (server.HasMoveRequestHandlerFactory()) { knownAbstractSyntaxes.push_back(UID_MOVEStudyRootQueryRetrieveInformationModel); } const char* transferSyntaxes[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; int numTransferSyntaxes = 0; cond = ASC_receiveAssociation(net, &assoc, /*opt_maxPDU*/ ASC_DEFAULTMAXPDU, NULL, NULL, /*opt_secureConnection*/ OFFalse, DUL_NOBLOCK, 1); if (cond == DUL_NOASSOCIATIONREQUEST) { // Timeout AssociationCleanup(assoc); return NULL; } // if some kind of error occured, take care of it if (cond.bad()) { LOG(ERROR) << "Receiving Association failed: " << cond.text(); // no matter what kind of error occurred, we need to do a cleanup AssociationCleanup(assoc); return NULL; } LOG(INFO) << "Association Received"; transferSyntaxes[0] = UID_LittleEndianExplicitTransferSyntax; transferSyntaxes[1] = UID_BigEndianExplicitTransferSyntax; transferSyntaxes[2] = UID_LittleEndianImplicitTransferSyntax; numTransferSyntaxes = 3; /* accept the Verification SOP Class if presented */ cond = ASC_acceptContextsWithPreferredTransferSyntaxes( assoc->params, &knownAbstractSyntaxes[0], knownAbstractSyntaxes.size(), transferSyntaxes, numTransferSyntaxes); if (cond.bad()) { LOG(INFO) << cond.text(); AssociationCleanup(assoc); return NULL; } /* the array of Storage SOP Class UIDs comes from dcuid.h */ cond = ASC_acceptContextsWithPreferredTransferSyntaxes( assoc->params, dcmAllStorageSOPClassUIDs, numberOfAllDcmStorageSOPClassUIDs, transferSyntaxes, numTransferSyntaxes); if (cond.bad()) { LOG(INFO) << cond.text(); AssociationCleanup(assoc); return NULL; } /* set our app title */ ASC_setAPTitles(assoc->params, NULL, NULL, server.GetApplicationEntityTitle().c_str()); /* acknowledge or reject this association */ cond = ASC_getApplicationContextName(assoc->params, buf); if ((cond.bad()) || strcmp(buf, UID_StandardApplicationContext) != 0) { /* reject: the application context name is not supported */ T_ASC_RejectParameters rej = { ASC_RESULT_REJECTEDPERMANENT, ASC_SOURCE_SERVICEUSER, ASC_REASON_SU_APPCONTEXTNAMENOTSUPPORTED }; LOG(INFO) << "Association Rejected: Bad Application Context Name: " << buf; cond = ASC_rejectAssociation(assoc, &rej); if (cond.bad()) { LOG(INFO) << cond.text(); } AssociationCleanup(assoc); return NULL; } /* check the AETs */ { DIC_AE callingTitle_C; DIC_AE calledTitle_C; DIC_AE callingIP_C; DIC_AE calledIP_C; if (ASC_getAPTitles(assoc->params, callingTitle_C, calledTitle_C, NULL).bad() || ASC_getPresentationAddresses(assoc->params, callingIP_C, calledIP_C).bad()) { T_ASC_RejectParameters rej = { ASC_RESULT_REJECTEDPERMANENT, ASC_SOURCE_SERVICEUSER, ASC_REASON_SU_NOREASON }; ASC_rejectAssociation(assoc, &rej); AssociationCleanup(assoc); return NULL; } std::string callingIP(/*OFSTRING_GUARD*/(callingIP_C)); std::string callingTitle(/*OFSTRING_GUARD*/(callingTitle_C)); std::string calledTitle(/*OFSTRING_GUARD*/(calledTitle_C)); Toolbox::ToUpperCase(callingIP); Toolbox::ToUpperCase(callingTitle); Toolbox::ToUpperCase(calledTitle); if (server.HasCalledApplicationEntityTitleCheck() && calledTitle != server.GetApplicationEntityTitle()) { T_ASC_RejectParameters rej = { ASC_RESULT_REJECTEDPERMANENT, ASC_SOURCE_SERVICEUSER, ASC_REASON_SU_CALLEDAETITLENOTRECOGNIZED }; ASC_rejectAssociation(assoc, &rej); AssociationCleanup(assoc); return NULL; } if (server.HasApplicationEntityFilter() && !server.GetApplicationEntityFilter().IsAllowed(callingIP, callingTitle)) { T_ASC_RejectParameters rej = { ASC_RESULT_REJECTEDPERMANENT, ASC_SOURCE_SERVICEUSER, ASC_REASON_SU_CALLINGAETITLENOTRECOGNIZED }; ASC_rejectAssociation(assoc, &rej); AssociationCleanup(assoc); return NULL; } } if (opt_rejectWithoutImplementationUID && strlen(assoc->params->theirImplementationClassUID) == 0) { /* reject: the no implementation Class UID provided */ T_ASC_RejectParameters rej = { ASC_RESULT_REJECTEDPERMANENT, ASC_SOURCE_SERVICEUSER, ASC_REASON_SU_NOREASON }; LOG(INFO) << "Association Rejected: No Implementation Class UID provided"; cond = ASC_rejectAssociation(assoc, &rej); if (cond.bad()) { LOG(INFO) << cond.text(); } AssociationCleanup(assoc); return NULL; } { cond = ASC_acknowledgeAssociation(assoc); if (cond.bad()) { LOG(ERROR) << cond.text(); AssociationCleanup(assoc); return NULL; } LOG(INFO) << "Association Acknowledged (Max Send PDV: " << assoc->sendPDVLength << ")"; if (ASC_countAcceptedPresentationContexts(assoc->params) == 0) LOG(INFO) << " (but no valid presentation contexts)"; } return new CommandDispatcher(server, assoc); }
void Association ::receive(Network &network, std::function<bool (const Association &)> authenticator, std::vector<std::string> const & aetitles, bool accept_all) { if(!network.is_initialized()) { throw Exception("Network is not initialized"); } if(this->is_associated()) { throw Exception("Already associated"); } OFCondition condition; condition = ASC_receiveAssociation( network.get_network(), &this->_association, ASC_DEFAULTMAXPDU); if(condition.bad()) { throw Exception(condition); } T_ASC_Parameters * const params = this->_association->params; DUL_ASSOCIATESERVICEPARAMETERS const dul = params->DULparams; // No peer port should be defined when receiving this->_peer_host_name = dul.callingPresentationAddress; this->_peer_port = 0; this->_peer_ae_title = dul.callingAPTitle; this->_own_ae_title = dul.calledAPTitle; // check Peer ae title // '*' => everybody allowed if (std::find(aetitles.begin(), aetitles.end(), "*") == aetitles.end() && std::find(aetitles.begin(), aetitles.end(), this->_peer_ae_title.c_str()) == aetitles.end()) { this->reject(RejectedPermanent, ULServiceUser, CallingAETitleNotRecognized); this->drop(); throw Exception("Bad AE Title"); } // Check Application Context Name char buf[BUFSIZ]; condition = ASC_getApplicationContextName(params, buf); if (condition.bad() || std::string(buf) != DICOM_STDAPPLICATIONCONTEXT) { // reject: application context name not supported this->reject(RejectedPermanent, ULServiceUser, ApplicationContextNameNotSupported); this->drop(); throw Exception("Bad Application context name"); } if(accept_all) { unsigned int const pc_count = ASC_countPresentationContexts(params); for(unsigned int pc_index=0; pc_index<pc_count; ++pc_index) { T_ASC_PresentationContext pc; memset(&pc, 0, sizeof(pc)); ASC_getPresentationContext(params, pc_index, &pc); for(unsigned int ts_index=0; ts_index<pc.transferSyntaxCount; ++ts_index) { std::string const abstract_syntax = pc.abstractSyntax; char const * abstract_syntax_data = abstract_syntax.c_str(); condition = ASC_acceptContextsWithTransferSyntax( this->_association->params, pc.proposedTransferSyntaxes[ts_index], 1, &abstract_syntax_data); if(condition.bad()) { this->reject(RejectedPermanent, ULServiceUser, NoReasonGiven); this->drop(); throw Exception(condition); } } } } else { for(auto const & context: this->_presentation_contexts) { for(std::size_t i = 0; i < context.transfer_syntaxes.size(); ++i) { char const * abstract_syntax = context.abstract_syntax.c_str(); char const * transfer_syntax = context.transfer_syntaxes[i].c_str(); condition = ASC_acceptContextsWithTransferSyntax( this->_association->params, transfer_syntax, 1, &abstract_syntax); if(condition.bad()) { this->reject(RejectedPermanent, ULServiceUser, NoReasonGiven); this->drop(); throw Exception(condition); } } } } // Get user identity information UserIdentityNegotiationSubItemRQ* identity = this->_association->params->DULparams.reqUserIdentNeg; this->_user_identity_primary_field = ""; this->_user_identity_secondary_field = ""; if (identity == NULL || identity->getIdentityType() == ASC_USER_IDENTITY_NONE) { this->_user_identity_type = UserIdentityType::None; } else if (identity->getIdentityType() != ASC_USER_IDENTITY_UNKNOWN) { this->_user_identity_type = (UserIdentityType)identity->getIdentityType(); // Get primary field char * primary_field; Uint16 primary_field_length; identity->getPrimField(primary_field, primary_field_length); // user is not NULL-terminated this->_user_identity_primary_field = std::string(primary_field, primary_field_length); if (identity->getIdentityType() == ASC_USER_IDENTITY_USER_PASSWORD) { // Get secondary field char * secondary_field; Uint16 secondary_field_length; identity->getSecField(secondary_field, secondary_field_length); // password is not NULL-terminated this->_user_identity_primary_field = std::string(secondary_field, secondary_field_length); } } else { throw Exception("Unknown user identity type"); } // Authentication if(authenticator(*this)) { condition = ASC_acknowledgeAssociation(this->_association); if(condition.bad()) { throw Exception(condition); } } else { this->reject(RejectedPermanent, ULServiceUser, NoReasonGiven); this->drop(); throw Exception("Bad Authentication"); } }