# HG changeset patch # User Sebastien Jodogne # Date 1468421559 -7200 # Node ID fabf7820d1f194149f15f0d40123dda498db5e08 # Parent 879f3be759ef454120c700d52345d99f7b14462d New configuration options: "DicomScuTimeout" and "DicomScpTimeout" + validation of non-negative options diff -r 879f3be759ef -r fabf7820d1f1 Core/HttpServer/MongooseServer.cpp --- a/Core/HttpServer/MongooseServer.cpp Wed Jul 13 16:10:25 2016 +0200 +++ b/Core/HttpServer/MongooseServer.cpp Wed Jul 13 16:52:39 2016 +0200 @@ -951,7 +951,7 @@ { Stop(); keepAlive_ = enabled; - LOG(WARNING) << "HTTP keep alive is " << (enabled ? "enabled" : "disabled"); + LOG(INFO) << "HTTP keep alive is " << (enabled ? "enabled" : "disabled"); } diff -r 879f3be759ef -r fabf7820d1f1 NEWS --- a/NEWS Wed Jul 13 16:10:25 2016 +0200 +++ b/NEWS Wed Jul 13 16:52:39 2016 +0200 @@ -2,6 +2,7 @@ =============================== * "Permissive" flag for URI "/modalities/{...}/store" to ignore C-Store transfer errors +* New configuration options: "DicomScuTimeout" and "DicomScpTimeout" Version 1.1.0 (2016/06/27) diff -r 879f3be759ef -r fabf7820d1f1 OrthancServer/DicomProtocol/DicomServer.cpp --- a/OrthancServer/DicomProtocol/DicomServer.cpp Wed Jul 13 16:10:25 2016 +0200 +++ b/OrthancServer/DicomProtocol/DicomServer.cpp Wed Jul 13 16:52:39 2016 +0200 @@ -121,10 +121,13 @@ return port_; } - void DicomServer::SetAssociationTimeout(uint32_t timeout) + void DicomServer::SetAssociationTimeout(uint32_t seconds) { + LOG(INFO) << "Setting timeout for DICOM connections if Orthanc acts as SCP (server): " + << seconds << " seconds (0 = no timeout)"; + Stop(); - associationTimeout_ = timeout; + associationTimeout_ = seconds; } uint32_t DicomServer::GetAssociationTimeout() const @@ -296,15 +299,9 @@ { Stop(); - uint32_t timeout = associationTimeout_; - if (timeout == 0) - { - timeout = 30; // Some safe value (30 seconds) if association timeout is disabled - } - /* initialize network, i.e. create an instance of T_ASC_Network*. */ OFCondition cond = ASC_initializeNetwork - (NET_ACCEPTOR, OFstatic_cast(int, port_), /*opt_acse_timeout*/ timeout, &pimpl_->network_); + (NET_ACCEPTOR, OFstatic_cast(int, port_), /*opt_acse_timeout*/ 30, &pimpl_->network_); if (cond.bad()) { LOG(ERROR) << "cannot create network: " << cond.text(); diff -r 879f3be759ef -r fabf7820d1f1 OrthancServer/DicomProtocol/DicomServer.h --- a/OrthancServer/DicomProtocol/DicomServer.h Wed Jul 13 16:10:25 2016 +0200 +++ b/OrthancServer/DicomProtocol/DicomServer.h Wed Jul 13 16:52:39 2016 +0200 @@ -71,7 +71,7 @@ void SetPortNumber(uint16_t port); uint16_t GetPortNumber() const; - void SetAssociationTimeout(uint32_t timeout); + void SetAssociationTimeout(uint32_t seconds); uint32_t GetAssociationTimeout() const; void SetCalledApplicationEntityTitleCheck(bool check); diff -r 879f3be759ef -r fabf7820d1f1 OrthancServer/DicomProtocol/DicomUserConnection.cpp --- a/OrthancServer/DicomProtocol/DicomUserConnection.cpp Wed Jul 13 16:10:25 2016 +0200 +++ b/OrthancServer/DicomProtocol/DicomUserConnection.cpp Wed Jul 13 16:52:39 2016 +0200 @@ -133,6 +133,9 @@ namespace Orthanc { + // By default, the timeout for DICOM SCU (client) connections is set to 10 seconds + static uint32_t defaultTimeout_ = 10; + struct DicomUserConnection::PImpl { // Connection state @@ -782,7 +785,7 @@ remotePort_ = 104; manufacturer_ = ModalityManufacturer_Generic; - SetTimeout(10); + SetTimeout(defaultTimeout_); pimpl_->net_ = NULL; pimpl_->params_ = NULL; pimpl_->assoc_ = NULL; @@ -1102,14 +1105,16 @@ void DicomUserConnection::SetTimeout(uint32_t seconds) { - if (seconds <= 0) + if (seconds == 0) { - throw OrthancException(ErrorCode_ParameterOutOfRange); + DisableTimeout(); } - - dcmConnectionTimeout.set(seconds); - pimpl_->dimseTimeout_ = seconds; - pimpl_->acseTimeout_ = 10; + else + { + dcmConnectionTimeout.set(seconds); + pimpl_->dimseTimeout_ = seconds; + pimpl_->acseTimeout_ = 10; // Timeout used during association negociation + } } @@ -1121,7 +1126,7 @@ */ dcmConnectionTimeout.set(-1); pimpl_->dimseTimeout_ = 0; - pimpl_->acseTimeout_ = 10; + pimpl_->acseTimeout_ = 10; // Timeout used during association negociation } @@ -1191,4 +1196,12 @@ ExecuteFind(result, pimpl_->assoc_, dataset, sopClass, true, NULL, pimpl_->dimseTimeout_); } + + + void DicomUserConnection::SetDefaultTimeout(uint32_t seconds) + { + LOG(INFO) << "Default timeout for DICOM connections if Orthanc acts as SCU (client): " + << seconds << " seconds (0 = no timeout)"; + defaultTimeout_ = seconds; + } } diff -r 879f3be759ef -r fabf7820d1f1 OrthancServer/DicomProtocol/DicomUserConnection.h --- a/OrthancServer/DicomProtocol/DicomUserConnection.h Wed Jul 13 16:10:25 2016 +0200 +++ b/OrthancServer/DicomProtocol/DicomUserConnection.h Wed Jul 13 16:52:39 2016 +0200 @@ -175,5 +175,7 @@ void FindWorklist(DicomFindAnswers& result, ParsedDicomFile& query); + + static void SetDefaultTimeout(uint32_t seconds); }; } diff -r 879f3be759ef -r fabf7820d1f1 OrthancServer/OrthancInitialization.cpp --- a/OrthancServer/OrthancInitialization.cpp Wed Jul 13 16:10:25 2016 +0200 +++ b/OrthancServer/OrthancInitialization.cpp Wed Jul 13 16:52:39 2016 +0200 @@ -577,6 +577,23 @@ } + unsigned int Configuration::GetGlobalUnsignedIntegerParameter(const std::string& parameter, + unsigned int defaultValue) + { + int v = GetGlobalIntegerParameter(parameter, defaultValue); + + if (v < 0) + { + LOG(ERROR) << "The configuration option \"" << parameter << "\" must be a positive integer"; + throw OrthancException(ErrorCode_BadParameterType); + } + else + { + return static_cast(v); + } + } + + bool Configuration::GetGlobalBoolParameter(const std::string& parameter, bool defaultValue) { diff -r 879f3be759ef -r fabf7820d1f1 OrthancServer/OrthancInitialization.h --- a/OrthancServer/OrthancInitialization.h Wed Jul 13 16:10:25 2016 +0200 +++ b/OrthancServer/OrthancInitialization.h Wed Jul 13 16:52:39 2016 +0200 @@ -64,6 +64,9 @@ static int GetGlobalIntegerParameter(const std::string& parameter, int defaultValue); + static unsigned int GetGlobalUnsignedIntegerParameter(const std::string& parameter, + unsigned int defaultValue); + static bool GetGlobalBoolParameter(const std::string& parameter, bool defaultValue); diff -r 879f3be759ef -r fabf7820d1f1 OrthancServer/OrthancRestApi/OrthancRestSystem.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp Wed Jul 13 16:10:25 2016 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp Wed Jul 13 16:52:39 2016 +0200 @@ -55,8 +55,8 @@ result["DatabaseVersion"] = OrthancRestApi::GetIndex(call).GetDatabaseVersion(); result["DicomAet"] = Configuration::GetGlobalStringParameter("DicomAet", "ORTHANC"); - result["DicomPort"] = Configuration::GetGlobalIntegerParameter("DicomPort", 4242); - result["HttpPort"] = Configuration::GetGlobalIntegerParameter("HttpPort", 8042); + result["DicomPort"] = Configuration::GetGlobalUnsignedIntegerParameter("DicomPort", 4242); + result["HttpPort"] = Configuration::GetGlobalUnsignedIntegerParameter("HttpPort", 8042); result["Name"] = Configuration::GetGlobalStringParameter("Name", ""); result["Version"] = ORTHANC_VERSION; diff -r 879f3be759ef -r fabf7820d1f1 OrthancServer/ServerContext.cpp --- a/OrthancServer/ServerContext.cpp Wed Jul 13 16:10:25 2016 +0200 +++ b/OrthancServer/ServerContext.cpp Wed Jul 13 16:52:39 2016 +0200 @@ -106,16 +106,16 @@ storeMD5_(true), provider_(*this), dicomCache_(provider_, DICOM_CACHE_SIZE), - scheduler_(Configuration::GetGlobalIntegerParameter("LimitJobs", 10)), + scheduler_(Configuration::GetGlobalUnsignedIntegerParameter("LimitJobs", 10)), lua_(*this), #if ORTHANC_PLUGINS_ENABLED == 1 plugins_(NULL), #endif done_(false), - queryRetrieveArchive_(Configuration::GetGlobalIntegerParameter("QueryRetrieveSize", 10)), + queryRetrieveArchive_(Configuration::GetGlobalUnsignedIntegerParameter("QueryRetrieveSize", 10)), defaultLocalAet_(Configuration::GetGlobalStringParameter("DicomAet", "ORTHANC")) { - uint64_t s = Configuration::GetGlobalIntegerParameter("DicomAssociationCloseDelay", 5); // In seconds + uint64_t s = Configuration::GetGlobalUnsignedIntegerParameter("DicomAssociationCloseDelay", 5); // In seconds scu_.SetMillisecondsBeforeClose(s * 1000); // Milliseconds are expected here listeners_.push_back(ServerListener(lua_, "Lua")); diff -r 879f3be759ef -r fabf7820d1f1 OrthancServer/ServerIndex.cpp --- a/OrthancServer/ServerIndex.cpp Wed Jul 13 16:10:25 2016 +0200 +++ b/OrthancServer/ServerIndex.cpp Wed Jul 13 16:52:39 2016 +0200 @@ -1848,7 +1848,7 @@ void ServerIndex::UnstableResourcesMonitorThread(ServerIndex* that) { - int stableAge = Configuration::GetGlobalIntegerParameter("StableAge", 60); + int stableAge = Configuration::GetGlobalUnsignedIntegerParameter("StableAge", 60); if (stableAge <= 0) { stableAge = 60; diff -r 879f3be759ef -r fabf7820d1f1 OrthancServer/main.cpp --- a/OrthancServer/main.cpp Wed Jul 13 16:10:25 2016 +0200 +++ b/OrthancServer/main.cpp Wed Jul 13 16:52:39 2016 +0200 @@ -111,8 +111,8 @@ { std::auto_ptr result(new OrthancFindRequestHandler(context_)); - result->SetMaxResults(Configuration::GetGlobalIntegerParameter("LimitFindResults", 0)); - result->SetMaxInstances(Configuration::GetGlobalIntegerParameter("LimitFindInstances", 0)); + result->SetMaxResults(Configuration::GetGlobalUnsignedIntegerParameter("LimitFindResults", 0)); + result->SetMaxInstances(Configuration::GetGlobalUnsignedIntegerParameter("LimitFindInstances", 0)); if (result->GetMaxResults() == 0) { @@ -722,7 +722,7 @@ // HTTP server MyIncomingHttpRequestFilter httpFilter(context, plugins); MongooseServer httpServer; - httpServer.SetPortNumber(Configuration::GetGlobalIntegerParameter("HttpPort", 8042)); + httpServer.SetPortNumber(Configuration::GetGlobalUnsignedIntegerParameter("HttpPort", 8042)); httpServer.SetRemoteAccessAllowed(Configuration::GetGlobalBoolParameter("RemoteAccessAllowed", false)); httpServer.SetKeepAliveEnabled(Configuration::GetGlobalBoolParameter("KeepAlive", false)); httpServer.SetHttpCompressionEnabled(Configuration::GetGlobalBoolParameter("HttpCompressionEnabled", true)); @@ -784,6 +784,8 @@ dicomServer.SetStoreRequestHandlerFactory(serverFactory); dicomServer.SetMoveRequestHandlerFactory(serverFactory); dicomServer.SetFindRequestHandlerFactory(serverFactory); + dicomServer.SetAssociationTimeout(Configuration::GetGlobalUnsignedIntegerParameter("DicomScpTimeout", 30)); + #if ORTHANC_PLUGINS_ENABLED == 1 if (plugins != NULL) @@ -805,7 +807,7 @@ } #endif - dicomServer.SetPortNumber(Configuration::GetGlobalIntegerParameter("DicomPort", 4242)); + dicomServer.SetPortNumber(Configuration::GetGlobalUnsignedIntegerParameter("DicomPort", 4242)); dicomServer.SetApplicationEntityTitle(Configuration::GetGlobalStringParameter("DicomAet", "ORTHANC")); dicomServer.SetApplicationEntityFilter(dicomFilter); @@ -936,14 +938,17 @@ HttpClient::ConfigureSsl(Configuration::GetGlobalBoolParameter("HttpsVerifyPeers", true), Configuration::GetGlobalStringParameter("HttpsCACertificates", "")); - HttpClient::SetDefaultTimeout(Configuration::GetGlobalIntegerParameter("HttpTimeout", 0)); + HttpClient::SetDefaultTimeout(Configuration::GetGlobalUnsignedIntegerParameter("HttpTimeout", 0)); HttpClient::SetDefaultProxy(Configuration::GetGlobalStringParameter("HttpProxy", "")); + + DicomUserConnection::SetDefaultTimeout(Configuration::GetGlobalUnsignedIntegerParameter("DicomScuTimeout", 10)); + context.SetCompressionEnabled(Configuration::GetGlobalBoolParameter("StorageCompression", false)); context.SetStoreMD5ForAttachments(Configuration::GetGlobalBoolParameter("StoreMD5ForAttachments", true)); try { - context.GetIndex().SetMaximumPatientCount(Configuration::GetGlobalIntegerParameter("MaximumPatientCount", 0)); + context.GetIndex().SetMaximumPatientCount(Configuration::GetGlobalUnsignedIntegerParameter("MaximumPatientCount", 0)); } catch (...) { @@ -952,7 +957,7 @@ try { - uint64_t size = Configuration::GetGlobalIntegerParameter("MaximumStorageSize", 0); + uint64_t size = Configuration::GetGlobalUnsignedIntegerParameter("MaximumStorageSize", 0); context.GetIndex().SetMaximumStorageSize(size * 1024 * 1024); } catch (...) diff -r 879f3be759ef -r fabf7820d1f1 Resources/Configuration.json --- a/Resources/Configuration.json Wed Jul 13 16:10:25 2016 +0200 +++ b/Resources/Configuration.json Wed Jul 13 16:52:39 2016 +0200 @@ -106,6 +106,11 @@ // SOP classes (aka. "promiscuous mode") "UnknownSopClassAccepted" : false, + // Set the timeout (in seconds) after which the DICOM associations + // are closed by the Orthanc SCP (server) if no further DIMSE + // command is received from the SCU (client). + "DicomScpTimeout" : 30, + /** @@ -158,6 +163,11 @@ // "clearcanvas" : [ "CLEARCANVAS", "192.168.1.1", 104, "ClearCanvas" ] }, + // The timeout (in seconds) after which the DICOM associations are + // considered as closed by the Orthanc SCU (client) if the remote + // DICOM SCP (server) does not answer. + "DicomScuTimeout" : 10, + // The list of the known Orthanc peers "OrthancPeers" : { /**