# HG changeset patch # User Sebastien Jodogne # Date 1403687291 -7200 # Node ID 83489fddd8c53200bbf6ae76b12d160798213b59 # Parent 4864b3e304be53dc70caa20bf547611fe9f29dd0 Options to limit the number of results for an incoming C-FIND query diff -r 4864b3e304be -r 83489fddd8c5 NEWS --- a/NEWS Wed Jun 25 09:06:34 2014 +0200 +++ b/NEWS Wed Jun 25 11:08:11 2014 +0200 @@ -2,6 +2,7 @@ =============================== * Official support of OS X (Darwin) +* Options to limit the number of results for an incoming C-FIND query * Support of kFreeBSD diff -r 4864b3e304be -r 83489fddd8c5 OrthancServer/DicomProtocol/IFindRequestHandler.h --- a/OrthancServer/DicomProtocol/IFindRequestHandler.h Wed Jun 25 09:06:34 2014 +0200 +++ b/OrthancServer/DicomProtocol/IFindRequestHandler.h Wed Jun 25 11:08:11 2014 +0200 @@ -47,7 +47,13 @@ { } - virtual void Handle(DicomFindAnswers& answers, + /** + * Can throw exceptions. Returns "false" iff too many results have + * to be returned. In such a case, a "Matching terminated due to + * Cancel request" DIMSE code would be returned. + * https://www.dabsoft.ch/dicom/4/V.4.1/ + **/ + virtual bool Handle(DicomFindAnswers& answers, const DicomMap& input, const std::string& callingAETitle) = 0; }; diff -r 4864b3e304be -r 83489fddd8c5 OrthancServer/Internals/FindScp.cpp --- a/OrthancServer/Internals/FindScp.cpp Wed Jun 25 09:06:34 2014 +0200 +++ b/OrthancServer/Internals/FindScp.cpp Wed Jun 25 11:08:11 2014 +0200 @@ -100,6 +100,7 @@ DicomFindAnswers answers_; DcmDataset* lastRequest_; const std::string* callingAETitle_; + bool noCroppingOfResults_; }; @@ -125,12 +126,12 @@ try { - data.handler_->Handle(data.answers_, data.input_, *data.callingAETitle_); + data.noCroppingOfResults_ = data.handler_->Handle(data.answers_, data.input_, *data.callingAETitle_); } catch (OrthancException& e) { // Internal error! - LOG(ERROR) << "IFindRequestHandler Failed: " << e.What(); + LOG(ERROR) << "C-FIND request handler has failed: " << e.What(); response->DimseStatus = STATUS_FIND_Failed_UnableToProcess; *responseIdentifiers = NULL; return; @@ -148,12 +149,21 @@ if (responseCount <= static_cast(data.answers_.GetSize())) { + // There are pending results that are still to be sent response->DimseStatus = STATUS_Pending; *responseIdentifiers = ToDcmtkBridge::Convert(data.answers_.GetAnswer(responseCount - 1)); } + else if (data.noCroppingOfResults_) + { + // Success: All the results have been sent + response->DimseStatus = STATUS_Success; + *responseIdentifiers = NULL; + } else { - response->DimseStatus = STATUS_Success; + // Success, but the results were too numerous and had to be cropped + LOG(WARNING) << "Too many results for an incoming C-FIND query"; + response->DimseStatus = STATUS_FIND_Cancel_MatchingTerminatedDueToCancelRequest; *responseIdentifiers = NULL; } } @@ -170,6 +180,7 @@ data.lastRequest_ = NULL; data.handler_ = &handler; data.callingAETitle_ = &callingAETitle; + data.noCroppingOfResults_ = true; OFCondition cond = DIMSE_findProvider(assoc, presID, &msg->msg.CFindRQ, FindScpCallback, &data, diff -r 4864b3e304be -r 83489fddd8c5 OrthancServer/OrthancFindRequestHandler.cpp --- a/OrthancServer/OrthancFindRequestHandler.cpp Wed Jun 25 09:06:34 2014 +0200 +++ b/OrthancServer/OrthancFindRequestHandler.cpp Wed Jun 25 11:08:11 2014 +0200 @@ -442,7 +442,26 @@ } - void OrthancFindRequestHandler::Handle(DicomFindAnswers& answers, + bool OrthancFindRequestHandler::HasReachedLimit(const DicomFindAnswers& answers, + ResourceType level) const + { + switch (level) + { + case ResourceType_Patient: + case ResourceType_Study: + case ResourceType_Series: + return (maxResults_ != 0 && answers.GetSize() >= maxResults_); + + case ResourceType_Instance: + return (maxInstances_ != 0 && answers.GetSize() >= maxInstances_); + + default: + throw OrthancException(ErrorCode_InternalError); + } + } + + + bool OrthancFindRequestHandler::Handle(DicomFindAnswers& answers, const DicomMap& input, const std::string& callingAETitle) { @@ -580,6 +599,12 @@ if (Matches(info, query)) { + if (HasReachedLimit(answers, level)) + { + // Too many results, stop before recording this new match + return false; + } + AddAnswer(answers, info, query); } } @@ -589,6 +614,8 @@ // This resource has probably been deleted during the find request } } + + return true; // All the matching resources have been returned } } diff -r 4864b3e304be -r 83489fddd8c5 OrthancServer/OrthancFindRequestHandler.h --- a/OrthancServer/OrthancFindRequestHandler.h Wed Jun 25 09:06:34 2014 +0200 +++ b/OrthancServer/OrthancFindRequestHandler.h Wed Jun 25 11:08:11 2014 +0200 @@ -41,15 +41,42 @@ { private: ServerContext& context_; + unsigned int maxResults_; + unsigned int maxInstances_; + + bool HasReachedLimit(const DicomFindAnswers& answers, + ResourceType level) const; public: OrthancFindRequestHandler(ServerContext& context) : - context_(context) + context_(context), + maxResults_(0), + maxInstances_(0) { } - virtual void Handle(DicomFindAnswers& answers, + virtual bool Handle(DicomFindAnswers& answers, const DicomMap& input, const std::string& callingAETitle); + + unsigned int GetMaxResults() const + { + return maxResults_; + } + + void SetMaxResults(unsigned int results) + { + maxResults_ = results; + } + + unsigned int GetMaxInstances() const + { + return maxInstances_; + } + + void SetMaxInstances(unsigned int instances) + { + maxInstances_ = instances; + } }; } diff -r 4864b3e304be -r 83489fddd8c5 OrthancServer/main.cpp --- a/OrthancServer/main.cpp Wed Jun 25 09:06:34 2014 +0200 +++ b/OrthancServer/main.cpp Wed Jun 25 11:08:11 2014 +0200 @@ -98,7 +98,32 @@ virtual IFindRequestHandler* ConstructFindRequestHandler() { - return new OrthancFindRequestHandler(context_); + std::auto_ptr result(new OrthancFindRequestHandler(context_)); + + result->SetMaxResults(Configuration::GetGlobalIntegerParameter("LimitFindResults", 0)); + result->SetMaxInstances(Configuration::GetGlobalIntegerParameter("LimitFindInstances", 0)); + + if (result->GetMaxResults() == 0) + { + LOG(INFO) << "No limit on the number of C-FIND results at the Patient, Study and Series levels"; + } + else + { + LOG(INFO) << "Maximum " << result->GetMaxResults() + << " results for C-FIND queries at the Patient, Study and Series levels"; + } + + if (result->GetMaxInstances() == 0) + { + LOG(INFO) << "No limit on the number of C-FIND results at the Instance level"; + } + else + { + LOG(INFO) << "Maximum " << result->GetMaxInstances() + << " instances will be returned for C-FIND queries at the Instance level"; + } + + return result.release(); } virtual IMoveRequestHandler* ConstructMoveRequestHandler() diff -r 4864b3e304be -r 83489fddd8c5 Resources/Configuration.json --- a/Resources/Configuration.json Wed Jun 25 09:06:34 2014 +0200 +++ b/Resources/Configuration.json Wed Jun 25 11:08:11 2014 +0200 @@ -160,5 +160,14 @@ // will be computed and stored in the Orthanc database. This // information can be used to detect disk corruption, at the price // of a small performance overhead. - "StoreMD5ForAttachments" : true + "StoreMD5ForAttachments" : true, + + // The maximum number of results for a single C-FIND request at the + // Patient, Study or Series level. Setting this option to "0" means + // no limit. + "LimitFindResults" : 0, + + // The maximum number of results for a single C-FIND request at the + // Instance level. Setting this option to "0" means no limit. + "LimitFindInstances" : 0 }