# HG changeset patch # User Sebastien Jodogne # Date 1587479639 -7200 # Node ID 67f988f42cef94aa31724e8393a0f7c689c454bc # Parent 44bfcfdf42e8de728e1fafe5a1cf4adc1353db2f# Parent dd0fcbf6a791522999877e6a059599aa1e6e5bd8 integration mainline->transcoding diff -r 44bfcfdf42e8 -r 67f988f42cef Core/DicomNetworking/IDicomConnectionManager.h --- a/Core/DicomNetworking/IDicomConnectionManager.h Mon Apr 20 14:04:14 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2020 Osimis S.A., Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * In addition, as a special exception, the copyright holders of this - * program give permission to link the code of its release with the - * OpenSSL project's "OpenSSL" library (or with modified versions of it - * that use the same license as the "OpenSSL" library), and distribute - * the linked executables. You must obey the GNU General Public License - * in all respects for all of the code used other than "OpenSSL". If you - * modify file(s) with this exception, you may extend this exception to - * your version of the file(s), but you are not obligated to do so. If - * you do not wish to do so, delete this exception statement from your - * version. If you delete this exception statement from all source files - * in the program, then also delete it here. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - **/ - - -#pragma once - -#if !defined(ORTHANC_ENABLE_DCMTK_NETWORKING) -# error The macro ORTHANC_ENABLE_DCMTK_NETWORKING must be defined -#endif - -#if ORTHANC_ENABLE_DCMTK_NETWORKING == 0 - -namespace Orthanc -{ - // DICOM networking is disabled, this is just a void class - class IDicomConnectionManager : public boost::noncopyable - { - public: - virtual ~IDicomConnectionManager() - { - } - }; -} - -#else - -#include "DicomUserConnection.h" - -namespace Orthanc -{ - class IDicomConnectionManager : public boost::noncopyable - { - public: - virtual ~IDicomConnectionManager() - { - } - - class IResource : public boost::noncopyable - { - public: - virtual ~IResource() - { - } - - virtual DicomUserConnection& GetConnection() = 0; - }; - - virtual IResource* AcquireConnection(const std::string& localAet, - const RemoteModalityParameters& remote) = 0; - }; -} - -#endif diff -r 44bfcfdf42e8 -r 67f988f42cef Core/DicomNetworking/TimeoutDicomConnectionManager.cpp --- a/Core/DicomNetworking/TimeoutDicomConnectionManager.cpp Mon Apr 20 14:04:14 2020 +0200 +++ b/Core/DicomNetworking/TimeoutDicomConnectionManager.cpp Tue Apr 21 16:33:59 2020 +0200 @@ -44,64 +44,59 @@ return boost::posix_time::microsec_clock::universal_time(); } - class TimeoutDicomConnectionManager::Resource : public IDicomConnectionManager::IResource + + TimeoutDicomConnectionManager::Lock::Lock(TimeoutDicomConnectionManager& that, + const std::string& localAet, + const RemoteModalityParameters& remote) : + that_(that), + lock_(that_.mutex_) { - private: - TimeoutDicomConnectionManager& that_; + // Calling "Touch()" will be done by the "~Lock()" destructor + that_.OpenInternal(localAet, remote); + } - public: - Resource(TimeoutDicomConnectionManager& that) : - that_(that) + + TimeoutDicomConnectionManager::Lock::~Lock() + { + that_.TouchInternal(); + } + + + DicomUserConnection& TimeoutDicomConnectionManager::Lock::GetConnection() + { + if (that_.connection_.get() == NULL) { - if (that_.connection_.get() == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } + // The allocation should have been done by "that_.Open()" in the constructor + throw OrthancException(ErrorCode_InternalError); } - - ~Resource() + else { - that_.Touch(); - } - - DicomUserConnection& GetConnection() - { - assert(that_.connection_.get() != NULL); return *that_.connection_; } - }; + } - void TimeoutDicomConnectionManager::Touch() + // Mutex must be locked + void TimeoutDicomConnectionManager::TouchInternal() { lastUse_ = GetNow(); } - void TimeoutDicomConnectionManager::CheckTimeoutInternal() + // Mutex must be locked + void TimeoutDicomConnectionManager::OpenInternal(const std::string& localAet, + const RemoteModalityParameters& remote) { - if (connection_.get() != NULL && - (GetNow() - lastUse_) >= timeout_) + if (connection_.get() == NULL || + !connection_->IsSameAssociation(localAet, remote)) { - Close(); + connection_.reset(new DicomUserConnection(localAet, remote)); } } - void TimeoutDicomConnectionManager::SetTimeout(unsigned int timeout) - { - timeout_ = boost::posix_time::milliseconds(timeout); - CheckTimeoutInternal(); - } - - - unsigned int TimeoutDicomConnectionManager::GetTimeout() - { - return static_cast(timeout_.total_milliseconds()); - } - - - void TimeoutDicomConnectionManager::Close() + // Mutex must be locked + void TimeoutDicomConnectionManager::CloseInternal() { if (connection_.get() != NULL) { @@ -113,22 +108,29 @@ } - void TimeoutDicomConnectionManager::CheckTimeout() + void TimeoutDicomConnectionManager::SetInactivityTimeout(unsigned int milliseconds) { - CheckTimeoutInternal(); + boost::mutex::scoped_lock lock(mutex_); + timeout_ = boost::posix_time::milliseconds(milliseconds); + CloseInternal(); } - IDicomConnectionManager::IResource* - TimeoutDicomConnectionManager::AcquireConnection(const std::string& localAet, - const RemoteModalityParameters& remote) + unsigned int TimeoutDicomConnectionManager::GetInactivityTimeout() { - if (connection_.get() == NULL || - !connection_->IsSameAssociation(localAet, remote)) + boost::mutex::scoped_lock lock(mutex_); + return static_cast(timeout_.total_milliseconds()); + } + + + void TimeoutDicomConnectionManager::CloseIfInactive() + { + boost::mutex::scoped_lock lock(mutex_); + + if (connection_.get() != NULL && + (GetNow() - lastUse_) >= timeout_) { - connection_.reset(new DicomUserConnection(localAet, remote)); + CloseInternal(); } - - return new Resource(*this); } } diff -r 44bfcfdf42e8 -r 67f988f42cef Core/DicomNetworking/TimeoutDicomConnectionManager.h --- a/Core/DicomNetworking/TimeoutDicomConnectionManager.h Mon Apr 20 14:04:14 2020 +0200 +++ b/Core/DicomNetworking/TimeoutDicomConnectionManager.h Tue Apr 21 16:33:59 2020 +0200 @@ -33,72 +33,72 @@ #pragma once -#include "IDicomConnectionManager.h" +#if !defined(ORTHANC_ENABLE_DCMTK_NETWORKING) +# error The macro ORTHANC_ENABLE_DCMTK_NETWORKING must be defined +#endif -#if ORTHANC_ENABLE_DCMTK_NETWORKING == 0 +#if ORTHANC_ENABLE_DCMTK_NETWORKING != 1 +# error The macro ORTHANC_ENABLE_DCMTK_NETWORKING must be 1 to use this file +#endif + + +#include "../Compatibility.h" +#include "DicomUserConnection.h" + +#include +#include namespace Orthanc { - class TimeoutDicomConnectionManager : public IDicomConnectionManager - { - public: - void SetTimeout(unsigned int timeout) - { - } - - unsigned int GetTimeout() - { - return 0; - } - - void Close() - { - } - - void CheckTimeout() - { - } - }; -} - -#else - -#include "../Compatibility.h" - -#include - -namespace Orthanc -{ - class TimeoutDicomConnectionManager : public IDicomConnectionManager + /** + * This class corresponds to a singleton to a DICOM SCU connection. + **/ + class TimeoutDicomConnectionManager : public boost::noncopyable { private: - class Resource; - + boost::mutex mutex_; std::unique_ptr connection_; boost::posix_time::ptime lastUse_; boost::posix_time::time_duration timeout_; - void Touch(); + // Mutex must be locked + void TouchInternal(); - void CheckTimeoutInternal(); + // Mutex must be locked + void OpenInternal(const std::string& localAet, + const RemoteModalityParameters& remote); + + // Mutex must be locked + void CloseInternal(); public: + class Lock : public boost::noncopyable + { + private: + TimeoutDicomConnectionManager& that_; + boost::mutex::scoped_lock lock_; + + public: + Lock(TimeoutDicomConnectionManager& that, + const std::string& localAet, + const RemoteModalityParameters& remote); + + ~Lock(); + + DicomUserConnection& GetConnection(); + }; + TimeoutDicomConnectionManager() : timeout_(boost::posix_time::milliseconds(1000)) { } - void SetTimeout(unsigned int timeout); + void SetInactivityTimeout(unsigned int milliseconds); - unsigned int GetTimeout(); + unsigned int GetInactivityTimeout(); // In milliseconds void Close(); - void CheckTimeout(); - - virtual IResource* AcquireConnection(const std::string& localAet, - const RemoteModalityParameters& remote); + void CloseIfInactive(); }; } - -#endif diff -r 44bfcfdf42e8 -r 67f988f42cef Core/DicomParsing/ParsedDicomFile.cpp --- a/Core/DicomParsing/ParsedDicomFile.cpp Mon Apr 20 14:04:14 2020 +0200 +++ b/Core/DicomParsing/ParsedDicomFile.cpp Tue Apr 21 16:33:59 2020 +0200 @@ -952,7 +952,7 @@ * equals the empty string, then proceed. In Orthanc <= 1.5.6, * an exception "Bad file format" was generated. * https://groups.google.com/d/msg/orthanc-users/aphG_h1AHVg/rfOTtTPTAgAJ - * https://bitbucket.org/sjodogne/orthanc/commits/4c45e018bd3de3cfa21d6efc6734673aaaee4435 + * https://hg.orthanc-server.com/orthanc/rev/4c45e018bd3de3cfa21d6efc6734673aaaee4435 **/ patientId.clear(); } diff -r 44bfcfdf42e8 -r 67f988f42cef Core/JobsEngine/Operations/IJobOperation.h --- a/Core/JobsEngine/Operations/IJobOperation.h Mon Apr 20 14:04:14 2020 +0200 +++ b/Core/JobsEngine/Operations/IJobOperation.h Tue Apr 21 16:33:59 2020 +0200 @@ -34,7 +34,6 @@ #pragma once #include "JobOperationValues.h" -#include "../../DicomNetworking/IDicomConnectionManager.h" namespace Orthanc { @@ -46,8 +45,7 @@ } virtual void Apply(JobOperationValues& outputs, - const JobOperationValue& input, - IDicomConnectionManager& dicomConnection) = 0; + const JobOperationValue& input) = 0; virtual void Serialize(Json::Value& result) const = 0; }; diff -r 44bfcfdf42e8 -r 67f988f42cef Core/JobsEngine/Operations/LogJobOperation.cpp --- a/Core/JobsEngine/Operations/LogJobOperation.cpp Mon Apr 20 14:04:14 2020 +0200 +++ b/Core/JobsEngine/Operations/LogJobOperation.cpp Tue Apr 21 16:33:59 2020 +0200 @@ -40,8 +40,7 @@ namespace Orthanc { void LogJobOperation::Apply(JobOperationValues& outputs, - const JobOperationValue& input, - IDicomConnectionManager& connectionManager) + const JobOperationValue& input) { switch (input.GetType()) { diff -r 44bfcfdf42e8 -r 67f988f42cef Core/JobsEngine/Operations/LogJobOperation.h --- a/Core/JobsEngine/Operations/LogJobOperation.h Mon Apr 20 14:04:14 2020 +0200 +++ b/Core/JobsEngine/Operations/LogJobOperation.h Tue Apr 21 16:33:59 2020 +0200 @@ -41,8 +41,7 @@ { public: virtual void Apply(JobOperationValues& outputs, - const JobOperationValue& input, - IDicomConnectionManager& connectionManager); + const JobOperationValue& input); virtual void Serialize(Json::Value& result) const { diff -r 44bfcfdf42e8 -r 67f988f42cef Core/JobsEngine/Operations/SequenceOfOperationsJob.cpp --- a/Core/JobsEngine/Operations/SequenceOfOperationsJob.cpp Mon Apr 20 14:04:14 2020 +0200 +++ b/Core/JobsEngine/Operations/SequenceOfOperationsJob.cpp Tue Apr 21 16:33:59 2020 +0200 @@ -43,7 +43,6 @@ { static const char* CURRENT = "Current"; static const char* DESCRIPTION = "Description"; - static const char* DICOM_TIMEOUT = "DicomTimeout"; static const char* NEXT_OPERATIONS = "Next"; static const char* OPERATION = "Operation"; static const char* OPERATIONS = "Operations"; @@ -127,7 +126,7 @@ return currentInput_ >= originalInputs_->GetSize() + workInputs_->GetSize(); } - void Step(IDicomConnectionManager& connectionManager) + void Step() { if (IsDone()) { @@ -146,7 +145,7 @@ } JobOperationValues outputs; - operation_->Apply(outputs, *input, connectionManager); + operation_->Apply(outputs, *input); if (!nextOperations_.empty()) { @@ -254,12 +253,6 @@ } - void SequenceOfOperationsJob::Lock::SetDicomAssociationTimeout(unsigned int timeout) - { - that_.connectionManager_.SetTimeout(timeout); - } - - size_t SequenceOfOperationsJob::Lock::AddOperation(IJobOperation* operation) { if (IsDone()) @@ -341,7 +334,6 @@ (*it)->SignalDone(*this); } - connectionManager_.Close(); return JobStepResult::Success(); } else @@ -360,11 +352,9 @@ if (current_ < operations_.size()) { - operations_[current_]->Step(connectionManager_); + operations_[current_]->Step(); } - connectionManager_.CheckTimeout(); - return JobStepResult::Continue(); } @@ -383,13 +373,6 @@ } - void SequenceOfOperationsJob::Stop(JobStopReason reason) - { - boost::mutex::scoped_lock lock(mutex_); - connectionManager_.Close(); - } - - float SequenceOfOperationsJob::GetProgress() { boost::mutex::scoped_lock lock(mutex_); @@ -420,7 +403,6 @@ value[DESCRIPTION] = description_; value[TRAILING_TIMEOUT] = static_cast(trailingTimeout_.total_milliseconds()); - value[DICOM_TIMEOUT] = connectionManager_.GetTimeout(); value[CURRENT] = static_cast(current_); Json::Value tmp = Json::arrayValue; @@ -454,8 +436,6 @@ description_ = SerializationToolbox::ReadString(serialized, DESCRIPTION); trailingTimeout_ = boost::posix_time::milliseconds (SerializationToolbox::ReadUnsignedInteger(serialized, TRAILING_TIMEOUT)); - connectionManager_.SetTimeout - (SerializationToolbox::ReadUnsignedInteger(serialized, DICOM_TIMEOUT)); current_ = SerializationToolbox::ReadUnsignedInteger(serialized, CURRENT); const Json::Value& ops = serialized[OPERATIONS]; diff -r 44bfcfdf42e8 -r 67f988f42cef Core/JobsEngine/Operations/SequenceOfOperationsJob.h --- a/Core/JobsEngine/Operations/SequenceOfOperationsJob.h Mon Apr 20 14:04:14 2020 +0200 +++ b/Core/JobsEngine/Operations/SequenceOfOperationsJob.h Tue Apr 21 16:33:59 2020 +0200 @@ -36,8 +36,6 @@ #include "../IJob.h" #include "IJobOperation.h" -#include "../../DicomNetworking/TimeoutDicomConnectionManager.h" - #include #include @@ -69,7 +67,6 @@ boost::condition_variable operationAdded_; boost::posix_time::time_duration trailingTimeout_; std::list observers_; - TimeoutDicomConnectionManager connectionManager_; void NotifyDone() const; @@ -109,8 +106,6 @@ } void SetTrailingOperationTimeout(unsigned int timeout); - - void SetDicomAssociationTimeout(unsigned int timeout); size_t AddOperation(IJobOperation* operation); @@ -134,7 +129,9 @@ virtual void Reset() ORTHANC_OVERRIDE; - virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE; + virtual void Stop(JobStopReason reason) ORTHANC_OVERRIDE + { + } virtual float GetProgress() ORTHANC_OVERRIDE; diff -r 44bfcfdf42e8 -r 67f988f42cef NEWS --- a/NEWS Mon Apr 20 14:04:14 2020 +0200 +++ b/NEWS Tue Apr 21 16:33:59 2020 +0200 @@ -2,6 +2,9 @@ =============================== +Version 1.6.1 (2020-04-21) +========================== + REST API -------- @@ -34,7 +37,6 @@ * Error reporting on failure while initializing SSL * Fix unit test ParsedDicomFile.ToJsonFlags2 on big-endian architectures * Avoid one memcpy of the DICOM buffer on "POST /instances" -* Default value of "HttpThreadsCount" reduced from 50 to 10 * Upgraded dependencies for static builds (notably on Windows): - civetweb 1.12 - openssl 1.1.1f diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/LuaScripting.cpp --- a/OrthancServer/LuaScripting.cpp Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/LuaScripting.cpp Tue Apr 21 16:33:59 2020 +0200 @@ -772,6 +772,8 @@ LOG(ERROR) << "Error while processing Lua events: " << e.What(); } } + + that->jobManager_.GetDicomConnectionManager().CloseIfInactive(); } } diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/LuaScripting.h --- a/OrthancServer/LuaScripting.h Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/LuaScripting.h Tue Apr 21 16:33:59 2020 +0200 @@ -136,5 +136,10 @@ void SignalJobSuccess(const std::string& jobId); void SignalJobFailure(const std::string& jobId); + + TimeoutDicomConnectionManager& GetDicomConnectionManager() + { + return jobManager_.GetDicomConnectionManager(); + } }; } diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/ServerJobs/LuaJobManager.cpp --- a/OrthancServer/ServerJobs/LuaJobManager.cpp Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/ServerJobs/LuaJobManager.cpp Tue Apr 21 16:33:59 2020 +0200 @@ -68,13 +68,16 @@ priority_(0), trailingTimeout_(5000) { + unsigned int dicomTimeout; + { OrthancConfiguration::ReaderLock lock; - dicomTimeout_ = lock.GetConfiguration().GetUnsignedIntegerParameter("DicomAssociationCloseDelay", 5); + dicomTimeout = lock.GetConfiguration().GetUnsignedIntegerParameter("DicomAssociationCloseDelay", 5); } + connectionManager_.SetInactivityTimeout(dicomTimeout * 1000); // Milliseconds expected LOG(INFO) << "Lua: DICOM associations will be closed after " - << dicomTimeout_ << " seconds of inactivity"; + << dicomTimeout << " seconds of inactivity"; } @@ -149,7 +152,6 @@ { jobLock_.reset(new SequenceOfOperationsJob::Lock(*that_.currentJob_)); jobLock_->SetTrailingOperationTimeout(that_.trailingTimeout_); - jobLock_->SetDicomAssociationTimeout(that_.dicomTimeout_ * 1000); // Milliseconds expected } } @@ -202,7 +204,7 @@ const RemoteModalityParameters& modality) { assert(jobLock_.get() != NULL); - return jobLock_->AddOperation(new StoreScuOperation(localAet, modality)); + return jobLock_->AddOperation(new StoreScuOperation(that_.connectionManager_, localAet, modality)); } diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/ServerJobs/LuaJobManager.h --- a/OrthancServer/ServerJobs/LuaJobManager.h Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/ServerJobs/LuaJobManager.h Tue Apr 21 16:33:59 2020 +0200 @@ -33,6 +33,7 @@ #pragma once +#include "../../Core/DicomNetworking/TimeoutDicomConnectionManager.h" #include "../../Core/DicomParsing/DicomModification.h" #include "../../Core/JobsEngine/JobsEngine.h" #include "../../Core/JobsEngine/Operations/SequenceOfOperationsJob.h" @@ -51,7 +52,7 @@ size_t maxOperations_; int priority_; unsigned int trailingTimeout_; - unsigned int dicomTimeout_; + TimeoutDicomConnectionManager connectionManager_; virtual void SignalDone(const SequenceOfOperationsJob& job); @@ -66,6 +67,11 @@ void AwakeTrailingSleep(); + TimeoutDicomConnectionManager& GetDicomConnectionManager() + { + return connectionManager_; + } + class Lock : public boost::noncopyable { private: diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/ServerJobs/Operations/DeleteResourceOperation.cpp --- a/OrthancServer/ServerJobs/Operations/DeleteResourceOperation.cpp Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/ServerJobs/Operations/DeleteResourceOperation.cpp Tue Apr 21 16:33:59 2020 +0200 @@ -43,8 +43,7 @@ namespace Orthanc { void DeleteResourceOperation::Apply(JobOperationValues& outputs, - const JobOperationValue& input, - IDicomConnectionManager& connectionManager) + const JobOperationValue& input) { switch (input.GetType()) { diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/ServerJobs/Operations/DeleteResourceOperation.h --- a/OrthancServer/ServerJobs/Operations/DeleteResourceOperation.h Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/ServerJobs/Operations/DeleteResourceOperation.h Tue Apr 21 16:33:59 2020 +0200 @@ -51,8 +51,7 @@ } virtual void Apply(JobOperationValues& outputs, - const JobOperationValue& input, - IDicomConnectionManager& connectionManager); + const JobOperationValue& input); virtual void Serialize(Json::Value& result) const { diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/ServerJobs/Operations/ModifyInstanceOperation.cpp --- a/OrthancServer/ServerJobs/Operations/ModifyInstanceOperation.cpp Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/ServerJobs/Operations/ModifyInstanceOperation.cpp Tue Apr 21 16:33:59 2020 +0200 @@ -81,8 +81,7 @@ } void ModifyInstanceOperation::Apply(JobOperationValues& outputs, - const JobOperationValue& input, - IDicomConnectionManager& connectionManager) + const JobOperationValue& input) { if (input.GetType() != JobOperationValue::Type_DicomInstance) { diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/ServerJobs/Operations/ModifyInstanceOperation.h --- a/OrthancServer/ServerJobs/Operations/ModifyInstanceOperation.h Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/ServerJobs/Operations/ModifyInstanceOperation.h Tue Apr 21 16:33:59 2020 +0200 @@ -67,8 +67,7 @@ } virtual void Apply(JobOperationValues& outputs, - const JobOperationValue& input, - IDicomConnectionManager& connectionManager); + const JobOperationValue& input); virtual void Serialize(Json::Value& target) const; }; diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/ServerJobs/Operations/StorePeerOperation.cpp --- a/OrthancServer/ServerJobs/Operations/StorePeerOperation.cpp Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/ServerJobs/Operations/StorePeerOperation.cpp Tue Apr 21 16:33:59 2020 +0200 @@ -44,8 +44,7 @@ namespace Orthanc { void StorePeerOperation::Apply(JobOperationValues& outputs, - const JobOperationValue& input, - IDicomConnectionManager& connectionManager) + const JobOperationValue& input) { // Configure the HTTP client HttpClient client(peer_, "instances"); diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/ServerJobs/Operations/StorePeerOperation.h --- a/OrthancServer/ServerJobs/Operations/StorePeerOperation.h Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/ServerJobs/Operations/StorePeerOperation.h Tue Apr 21 16:33:59 2020 +0200 @@ -57,8 +57,7 @@ } virtual void Apply(JobOperationValues& outputs, - const JobOperationValue& input, - IDicomConnectionManager& connectionManager); + const JobOperationValue& input); virtual void Serialize(Json::Value& result) const; }; diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/ServerJobs/Operations/StoreScuOperation.cpp --- a/OrthancServer/ServerJobs/Operations/StoreScuOperation.cpp Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/ServerJobs/Operations/StoreScuOperation.cpp Tue Apr 21 16:33:59 2020 +0200 @@ -43,18 +43,10 @@ namespace Orthanc { void StoreScuOperation::Apply(JobOperationValues& outputs, - const JobOperationValue& input, - IDicomConnectionManager& connectionManager) + const JobOperationValue& input) { - std::unique_ptr resource - (connectionManager.AcquireConnection(localAet_, modality_)); - - if (resource.get() == NULL) - { - LOG(ERROR) << "Lua: Cannot connect to modality: " << modality_.GetApplicationEntityTitle(); - return; - } - + TimeoutDicomConnectionManager::Lock lock(connectionManager_, localAet_, modality_); + if (input.GetType() != JobOperationValue::Type_DicomInstance) { throw OrthancException(ErrorCode_BadParameterType); @@ -72,7 +64,7 @@ instance.ReadDicom(dicom); std::string sopClassUid, sopInstanceUid; // Unused - resource->GetConnection().Store(sopClassUid, sopInstanceUid, dicom); + lock.GetConnection().Store(sopClassUid, sopInstanceUid, dicom); } catch (OrthancException& e) { @@ -93,7 +85,9 @@ } - StoreScuOperation::StoreScuOperation(const Json::Value& serialized) + StoreScuOperation::StoreScuOperation(TimeoutDicomConnectionManager& connectionManager, + const Json::Value& serialized) : + connectionManager_(connectionManager) { if (SerializationToolbox::ReadString(serialized, "Type") != "StoreScu" || !serialized.isMember("LocalAET")) diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/ServerJobs/Operations/StoreScuOperation.h --- a/OrthancServer/ServerJobs/Operations/StoreScuOperation.h Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/ServerJobs/Operations/StoreScuOperation.h Tue Apr 21 16:33:59 2020 +0200 @@ -34,25 +34,29 @@ #pragma once #include "../../../Core/JobsEngine/Operations/IJobOperation.h" -#include "../../../Core/DicomNetworking/RemoteModalityParameters.h" +#include "../../../Core/DicomNetworking/TimeoutDicomConnectionManager.h" namespace Orthanc { class StoreScuOperation : public IJobOperation { private: - std::string localAet_; - RemoteModalityParameters modality_; + TimeoutDicomConnectionManager& connectionManager_; + std::string localAet_; + RemoteModalityParameters modality_; public: - StoreScuOperation(const std::string& localAet, + StoreScuOperation(TimeoutDicomConnectionManager& connectionManager, + const std::string& localAet, const RemoteModalityParameters& modality) : + connectionManager_(connectionManager), localAet_(localAet), modality_(modality) { } - StoreScuOperation(const Json::Value& serialized); + StoreScuOperation(TimeoutDicomConnectionManager& connectionManager, + const Json::Value& serialized); const std::string& GetLocalAet() const { @@ -65,8 +69,7 @@ } virtual void Apply(JobOperationValues& outputs, - const JobOperationValue& input, - IDicomConnectionManager& manager); + const JobOperationValue& input); virtual void Serialize(Json::Value& result) const; }; diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/ServerJobs/Operations/SystemCallOperation.cpp --- a/OrthancServer/ServerJobs/Operations/SystemCallOperation.cpp Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/ServerJobs/Operations/SystemCallOperation.cpp Tue Apr 21 16:33:59 2020 +0200 @@ -74,8 +74,7 @@ void SystemCallOperation::Apply(JobOperationValues& outputs, - const JobOperationValue& input, - IDicomConnectionManager& connectionManager) + const JobOperationValue& input) { std::vector arguments = preArguments_; diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/ServerJobs/Operations/SystemCallOperation.h --- a/OrthancServer/ServerJobs/Operations/SystemCallOperation.h Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/ServerJobs/Operations/SystemCallOperation.h Tue Apr 21 16:33:59 2020 +0200 @@ -93,8 +93,7 @@ const std::string& GetPostArgument(size_t i) const; virtual void Apply(JobOperationValues& outputs, - const JobOperationValue& input, - IDicomConnectionManager& connectionManager); + const JobOperationValue& input); virtual void Serialize(Json::Value& result) const; }; diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/ServerJobs/OrthancJobUnserializer.cpp --- a/OrthancServer/ServerJobs/OrthancJobUnserializer.cpp Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/ServerJobs/OrthancJobUnserializer.cpp Tue Apr 21 16:33:59 2020 +0200 @@ -126,7 +126,8 @@ } else if (type == "StoreScu") { - return new StoreScuOperation(source); + return new StoreScuOperation( + context_.GetLuaScripting().GetDicomConnectionManager(), source); } else if (type == "SystemCall") { diff -r 44bfcfdf42e8 -r 67f988f42cef OrthancServer/main.cpp --- a/OrthancServer/main.cpp Mon Apr 20 14:04:14 2020 +0200 +++ b/OrthancServer/main.cpp Tue Apr 21 16:33:59 2020 +0200 @@ -906,7 +906,7 @@ httpDescribeErrors = lock.GetConfiguration().GetBooleanParameter("HttpDescribeErrors", true); // HTTP server - httpServer.SetThreadsCount(lock.GetConfiguration().GetUnsignedIntegerParameter("HttpThreadsCount", 10)); + httpServer.SetThreadsCount(lock.GetConfiguration().GetUnsignedIntegerParameter("HttpThreadsCount", 50)); httpServer.SetPortNumber(lock.GetConfiguration().GetUnsignedIntegerParameter("HttpPort", 8042)); httpServer.SetRemoteAccessAllowed(lock.GetConfiguration().GetBooleanParameter("RemoteAccessAllowed", false)); httpServer.SetKeepAliveEnabled(lock.GetConfiguration().GetBooleanParameter("KeepAlive", defaultKeepAlive)); diff -r 44bfcfdf42e8 -r 67f988f42cef Plugins/Include/orthanc/OrthancCPlugin.h --- a/Plugins/Include/orthanc/OrthancCPlugin.h Mon Apr 20 14:04:14 2020 +0200 +++ b/Plugins/Include/orthanc/OrthancCPlugin.h Tue Apr 21 16:33:59 2020 +0200 @@ -180,7 +180,7 @@ /** * For Microsoft Visual Studio, a compatibility "stdint.h" can be * downloaded at the following URL: - * https://bitbucket.org/sjodogne/orthanc/raw/default/Resources/ThirdParty/VisualStudio/stdint.h + * https://hg.orthanc-server.com/orthanc/raw-file/tip/Resources/ThirdParty/VisualStudio/stdint.h **/ #include diff -r 44bfcfdf42e8 -r 67f988f42cef Plugins/Samples/Basic/Plugin.c --- a/Plugins/Samples/Basic/Plugin.c Mon Apr 20 14:04:14 2020 +0200 +++ b/Plugins/Samples/Basic/Plugin.c Tue Apr 21 16:33:59 2020 +0200 @@ -446,7 +446,7 @@ sprintf(buf, "Incoming has pixel data: %d", hasPixelData); OrthancPluginLogWarning(context, buf); - // Reject all instances without pixel data + /* Reject all instances without pixel data */ return hasPixelData; } diff -r 44bfcfdf42e8 -r 67f988f42cef Resources/CMake/OrthancFrameworkParameters.cmake diff -r 44bfcfdf42e8 -r 67f988f42cef Resources/Configuration.json --- a/Resources/Configuration.json Mon Apr 20 14:04:14 2020 +0200 +++ b/Resources/Configuration.json Tue Apr 21 16:33:59 2020 +0200 @@ -391,11 +391,8 @@ // caveats: https://eklitzke.org/the-caveats-of-tcp-nodelay "TcpNoDelay" : true, - // Number of threads that are used by the embedded HTTP server. In - // Orthanc <= 1.6.0, the default value was 50. In Orthanc >= 1.6.1, - // default is 10 to prevent memory grow in basic setups. - // https://groups.google.com/d/msg/orthanc-users/qWqxpvCPv8g/Z8huoA5FDAAJ - "HttpThreadsCount" : 10, + // Number of threads that are used by the embedded HTTP server. + "HttpThreadsCount" : 50, // If this option is set to "false", Orthanc will run in index-only // mode. The DICOM files will not be stored on the drive. Note that @@ -406,7 +403,7 @@ // as new DICOM commands are issued. This option sets the number of // seconds of inactivity to wait before automatically closing a // DICOM association used by Lua. If set to 0, the connection is - // closed immediately. + // closed immediately. This option is only used in Lua scripts. "DicomAssociationCloseDelay" : 5, // Maximum number of query/retrieve DICOM requests that are diff -r 44bfcfdf42e8 -r 67f988f42cef Resources/DownloadOrthancFramework.cmake --- a/Resources/DownloadOrthancFramework.cmake Mon Apr 20 14:04:14 2020 +0200 +++ b/Resources/DownloadOrthancFramework.cmake Tue Apr 21 16:33:59 2020 +0200 @@ -114,6 +114,8 @@ set(ORTHANC_FRAMEWORK_MD5 "82323e8c49a667f658a3639ea4dbc336") elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.6.0") set(ORTHANC_FRAMEWORK_MD5 "eab428d6e53f61e847fa360bb17ebe25") + elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.6.1") + set(ORTHANC_FRAMEWORK_MD5 "3971f5de96ba71dc9d3f3690afeaa7c0") # Below this point are development snapshots that were used to # release some plugin, before an official release of the Orthanc @@ -216,7 +218,7 @@ else() message("Forking the Orthanc source repository using Mercurial") execute_process( - COMMAND ${ORTHANC_FRAMEWORK_HG} clone "https://bitbucket.org/sjodogne/orthanc" + COMMAND ${ORTHANC_FRAMEWORK_HG} clone "https://hg.orthanc-server.com/orthanc/" WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE Failure ) diff -r 44bfcfdf42e8 -r 67f988f42cef Resources/Samples/README.txt --- a/Resources/Samples/README.txt Mon Apr 20 14:04:14 2020 +0200 +++ b/Resources/Samples/README.txt Tue Apr 21 16:33:59 2020 +0200 @@ -2,6 +2,6 @@ the "OrthancContributed" repository on GitHub: https://github.com/jodogne/OrthancContributed -The integration tests of Orthanc provide a lot of samples about the +The integration tests of Orthanc provide many samples about the features of the REST API of Orthanc: -https://bitbucket.org/sjodogne/orthanc-tests/src/default/Tests/Tests.py +https://hg.orthanc-server.com/orthanc-tests/file/tip/Tests/Tests.py diff -r 44bfcfdf42e8 -r 67f988f42cef UnitTestsSources/MultiThreadingTests.cpp --- a/UnitTestsSources/MultiThreadingTests.cpp Mon Apr 20 14:04:14 2020 +0200 +++ b/UnitTestsSources/MultiThreadingTests.cpp Tue Apr 21 16:33:59 2020 +0200 @@ -1098,7 +1098,6 @@ StringOperationValue s2("world"); lock.AddInput(a, s1); lock.AddInput(a, s2); - lock.SetDicomAssociationTimeout(200); lock.SetTrailingOperationTimeout(300); } @@ -1284,7 +1283,6 @@ MemoryStorageArea storage_; SQLiteDatabaseWrapper db_; // The SQLite DB is in memory std::unique_ptr context_; - TimeoutDicomConnectionManager manager_; public: OrthancJobsSerialization() @@ -1407,27 +1405,31 @@ // StoreScuOperation { - RemoteModalityParameters modality; - modality.SetApplicationEntityTitle("REMOTE"); - modality.SetHost("192.168.1.1"); - modality.SetPortNumber(1000); - modality.SetManufacturer(ModalityManufacturer_StoreScp); + TimeoutDicomConnectionManager luaManager; + + { + RemoteModalityParameters modality; + modality.SetApplicationEntityTitle("REMOTE"); + modality.SetHost("192.168.1.1"); + modality.SetPortNumber(1000); + modality.SetManufacturer(ModalityManufacturer_StoreScp); - StoreScuOperation operation("TEST", modality); + StoreScuOperation operation(luaManager, "TEST", modality); - ASSERT_TRUE(CheckIdempotentSerialization(unserializer, operation)); - operation.Serialize(s); - } + ASSERT_TRUE(CheckIdempotentSerialization(unserializer, operation)); + operation.Serialize(s); + } - { - operation.reset(unserializer.UnserializeOperation(s)); + { + operation.reset(unserializer.UnserializeOperation(s)); - const StoreScuOperation& tmp = dynamic_cast(*operation); - ASSERT_EQ("REMOTE", tmp.GetRemoteModality().GetApplicationEntityTitle()); - ASSERT_EQ("192.168.1.1", tmp.GetRemoteModality().GetHost()); - ASSERT_EQ(1000, tmp.GetRemoteModality().GetPortNumber()); - ASSERT_EQ(ModalityManufacturer_StoreScp, tmp.GetRemoteModality().GetManufacturer()); - ASSERT_EQ("TEST", tmp.GetLocalAet()); + const StoreScuOperation& tmp = dynamic_cast(*operation); + ASSERT_EQ("REMOTE", tmp.GetRemoteModality().GetApplicationEntityTitle()); + ASSERT_EQ("192.168.1.1", tmp.GetRemoteModality().GetHost()); + ASSERT_EQ(1000, tmp.GetRemoteModality().GetPortNumber()); + ASSERT_EQ(ModalityManufacturer_StoreScp, tmp.GetRemoteModality().GetManufacturer()); + ASSERT_EQ("TEST", tmp.GetLocalAet()); + } } // SystemCallOperation diff -r 44bfcfdf42e8 -r 67f988f42cef UnitTestsSources/RestApiTests.cpp --- a/UnitTestsSources/RestApiTests.cpp Mon Apr 20 14:04:14 2020 +0200 +++ b/UnitTestsSources/RestApiTests.cpp Tue Apr 21 16:33:59 2020 +0200 @@ -121,22 +121,26 @@ HttpClient c; c.SetHttpsVerifyPeers(true); c.SetHttpsCACertificates("UnitTestsResults/bitbucket.cert"); - c.SetUrl("https://bitbucket.org/sjodogne/orthanc/raw/Orthanc-0.9.3/Resources/Configuration.json"); + + // Test file modified on 2020-04-20, in order to use a git + // repository on BitBucket instead of a Mercurial repository + // (because Mercurial support disappears on 2020-05-31) + c.SetUrl("https://bitbucket.org/osimis/orthanc-setup-samples/raw/master/docker/serve-folders/orthanc/serve-folders.json"); Json::Value v; c.Apply(v); - ASSERT_TRUE(v.isMember("LuaScripts")); + ASSERT_TRUE(v.isMember("ServeFolders")); } TEST(HttpClient, SslNoVerification) { HttpClient c; c.SetHttpsVerifyPeers(false); - c.SetUrl("https://bitbucket.org/sjodogne/orthanc/raw/Orthanc-0.9.3/Resources/Configuration.json"); + c.SetUrl("https://bitbucket.org/osimis/orthanc-setup-samples/raw/master/docker/serve-folders/orthanc/serve-folders.json"); Json::Value v; c.Apply(v); - ASSERT_TRUE(v.isMember("LuaScripts")); + ASSERT_TRUE(v.isMember("ServeFolders")); } #endif