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);
    }
Exemple #2
0
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");
    }
}