# HG changeset patch # User Sebastien Jodogne # Date 1645594589 -3600 # Node ID 95378de340d4d5e4eb4e0952875eb0f3a5a8aa7e # Parent 89f7d29a38c4bd068134eaa498c1d895db621b83# Parent 189ae9a37e01a5ffdfc98dd05d9e3ddfa6046c7b merge diff -r 89f7d29a38c4 -r 95378de340d4 OrthancFramework/Sources/MallocMemoryBuffer.cpp --- a/OrthancFramework/Sources/MallocMemoryBuffer.cpp Wed Feb 23 06:36:06 2022 +0100 +++ b/OrthancFramework/Sources/MallocMemoryBuffer.cpp Wed Feb 23 06:36:29 2022 +0100 @@ -57,11 +57,23 @@ void MallocMemoryBuffer::Assign(void* buffer, - size_t size, + uint64_t size, FreeFunction freeFunction) { Clear(); + if (size != 0 && + buffer == NULL) + { + throw OrthancException(ErrorCode_NullPointer); + } + + if (static_cast(static_cast(size)) != size) + { + freeFunction(buffer); + throw OrthancException(ErrorCode_InternalError, "Buffer larger than 4GB, which is too large for Orthanc running in 32bits"); + } + buffer_ = buffer; size_ = size; free_ = freeFunction; diff -r 89f7d29a38c4 -r 95378de340d4 OrthancFramework/Sources/MallocMemoryBuffer.h --- a/OrthancFramework/Sources/MallocMemoryBuffer.h Wed Feb 23 06:36:06 2022 +0100 +++ b/OrthancFramework/Sources/MallocMemoryBuffer.h Wed Feb 23 06:36:29 2022 +0100 @@ -52,7 +52,7 @@ void Clear(); void Assign(void* buffer, - size_t size, + uint64_t size, FreeFunction freeFunction); virtual void MoveToString(std::string& target) ORTHANC_OVERRIDE; diff -r 89f7d29a38c4 -r 95378de340d4 OrthancServer/Plugins/Engine/OrthancPlugins.cpp --- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Wed Feb 23 06:36:06 2022 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Wed Feb 23 06:36:29 2022 +0100 @@ -1156,7 +1156,6 @@ typedef std::list IncomingHttpRequestFilters2; typedef std::list IncomingDicomInstanceFilters; typedef std::list IncomingCStoreInstanceFilters; - typedef std::list ReceivedInstanceCallbacks; typedef std::list DecodeImageCallbacks; typedef std::list TranscoderCallbacks; typedef std::list JobsUnserializers; @@ -1180,7 +1179,7 @@ IncomingHttpRequestFilters2 incomingHttpRequestFilters2_; IncomingDicomInstanceFilters incomingDicomInstanceFilters_; IncomingCStoreInstanceFilters incomingCStoreInstanceFilters_; // New in Orthanc 1.10.0 - ReceivedInstanceCallbacks receivedInstanceCallbacks_; // New in Orthanc 1.10.0 + OrthancPluginReceivedInstanceCallback receivedInstanceCallback_; // New in Orthanc 1.10.0 RefreshMetricsCallbacks refreshMetricsCallbacks_; StorageCommitmentScpCallbacks storageCommitmentScpCallbacks_; std::unique_ptr storageArea_; @@ -1212,6 +1211,7 @@ context_(NULL), findCallback_(NULL), worklistCallback_(NULL), + receivedInstanceCallback_(NULL), argc_(1), argv_(NULL), databaseServerIdentifier_(databaseServerIdentifier), @@ -2285,72 +2285,29 @@ } - bool OrthancPlugins::ApplyReceivedInstanceCallbacks(const void* receivedDicom, - size_t receivedDicomSize, - void** modifiedDicomBufferData, - size_t& modifiedDicomBufferSize) + OrthancPluginReceivedInstanceCallbackResult OrthancPlugins::ApplyReceivedInstanceCallbacks( + MallocMemoryBuffer& modified, + const void* receivedDicom, + size_t receivedDicomSize) { - uint64_t modifiedDicomSize64 = 0; - *modifiedDicomBufferData = NULL; - boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_); - - for (PImpl::ReceivedInstanceCallbacks::const_iterator - callback = pimpl_->receivedInstanceCallbacks_.begin(); - callback != pimpl_->receivedInstanceCallbacks_.end(); ++callback) - { - OrthancPluginReceivedInstanceCallbackResult callbackResult = (*callback) (receivedDicom, - receivedDicomSize, - modifiedDicomBufferData, - &modifiedDicomSize64); - - if (callbackResult == OrthancPluginReceivedInstanceCallbackResult_Discard) - { - if (modifiedDicomSize64 > 0 || *modifiedDicomBufferData != NULL) - { - free(modifiedDicomBufferData); - throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback plugin is returning a modified buffer while it has discarded the instance"); - } - - CLOG(INFO, PLUGINS) << "A plugin has discarded the instance in its ReceivedInstanceCallback"; - return false; - } - else if (callbackResult == OrthancPluginReceivedInstanceCallbackResult_KeepAsIs) - { - if (modifiedDicomSize64 > 0 || *modifiedDicomBufferData != NULL) - { - free(modifiedDicomBufferData); - throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback plugin is returning a modified buffer while it has not modified the instance"); - } - return true; - } - else if (callbackResult == OrthancPluginReceivedInstanceCallbackResult_Modify) - { - if (modifiedDicomSize64 > 0 && modifiedDicomBufferData != NULL) - { - if (static_cast(modifiedDicomSize64) != modifiedDicomSize64) // Orthanc is running in 32bits and has received a > 4GB buffer - { - free(modifiedDicomBufferData); - throw OrthancException(ErrorCode_Plugin, "The Plugin has returned a > 4GB which is too large for Orthanc running in 32bits"); - } - - modifiedDicomBufferSize = static_cast(modifiedDicomSize64); - - CLOG(INFO, PLUGINS) << "A plugin has modified the instance in its ReceivedInstanceCallback"; - return true; - } - else - { - throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback plugin is not returning a modified buffer while it has modified the instance"); - } - } - else - { - throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback has returned an invalid value"); - } - } - - return true; + + if (pimpl_->receivedInstanceCallback_ == NULL) + { + return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs; + } + else + { + OrthancPluginReceivedInstanceCallbackResult callbackResult; + + { + OrthancPluginMemoryBuffer64 buffer; + callbackResult = (*pimpl_->receivedInstanceCallback_) (&buffer, receivedDicom, receivedDicomSize); + modified.Assign(buffer.data, buffer.size, ::free); + } + + return callbackResult; + } } void OrthancPlugins::SignalChangeInternal(OrthancPluginChangeType changeType, @@ -2584,8 +2541,16 @@ const _OrthancPluginReceivedInstanceCallback& p = *reinterpret_cast(parameters); - CLOG(INFO, PLUGINS) << "Plugin has registered a received instance callback"; - pimpl_->receivedInstanceCallbacks_.push_back(p.callback); + if (pimpl_->receivedInstanceCallback_ != NULL) + { + throw OrthancException(ErrorCode_Plugin, + "Can only register one plugin callback to process received instances"); + } + else + { + CLOG(INFO, PLUGINS) << "Plugin has registered a received instance callback"; + pimpl_->receivedInstanceCallback_ = p.callback; + } } void OrthancPlugins::RegisterRefreshMetricsCallback(const void* parameters) diff -r 89f7d29a38c4 -r 95378de340d4 OrthancServer/Plugins/Engine/OrthancPlugins.h --- a/OrthancServer/Plugins/Engine/OrthancPlugins.h Wed Feb 23 06:36:06 2022 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.h Wed Feb 23 06:36:29 2022 +0100 @@ -50,6 +50,7 @@ #include "../../../OrthancFramework/Sources/HttpServer/IHttpHandler.h" #include "../../../OrthancFramework/Sources/HttpServer/IIncomingHttpRequestFilter.h" #include "../../../OrthancFramework/Sources/JobsEngine/IJob.h" +#include "../../../OrthancFramework/Sources/MallocMemoryBuffer.h" #include "../../Sources/Database/IDatabaseWrapper.h" #include "../../Sources/IDicomImageDecoder.h" #include "../../Sources/IServerListener.h" @@ -275,10 +276,9 @@ virtual uint16_t FilterIncomingCStoreInstance(const DicomInstanceToStore& instance, const Json::Value& simplified) ORTHANC_OVERRIDE; - virtual bool ApplyReceivedInstanceCallbacks(const void* receivedDicomBuffer, - size_t receivedDicomBufferSize, - void** modifiedDicomBufferData, - size_t& modifiedDicomBufferSize); + OrthancPluginReceivedInstanceCallbackResult ApplyReceivedInstanceCallbacks(MallocMemoryBuffer& modified, + const void* receivedDicomBuffer, + size_t receivedDicomBufferSize); bool HasStorageArea() const; diff -r 89f7d29a38c4 -r 95378de340d4 OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h --- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Wed Feb 23 06:36:06 2022 +0100 +++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Wed Feb 23 06:36:29 2022 +0100 @@ -7780,19 +7780,19 @@ /** * @brief Callback to filter incoming DICOM instances received by - * Orthanc through C-Store. + * Orthanc through C-STORE. * * Signature of a callback function that is triggered whenever * Orthanc receives a new DICOM instance (through DICOM protocol), * and that answers whether this DICOM instance should be accepted * or discarded by Orthanc. If the instance is discarded, the callback - * can specify the C-Store error code. + * can specify the C-STORE error code. * * Note that the metadata information is not available * (i.e. GetInstanceMetadata() should not be used on "instance"). * * @param instance The received DICOM instance. - * @return 0 to accept the instance, any valid C-Store error code + * @return 0 to accept the instance, any valid C-STORE error code * to reject the instance, -1 if error. * @ingroup Callback **/ @@ -7807,7 +7807,7 @@ /** * @brief Register a callback to filter incoming DICOM instances - * received by Orthanc through C-Store. + * received by Orthanc through C-STORE. * * * @warning Your callback function will be called synchronously with @@ -7837,34 +7837,30 @@ /** * @brief Callback to possibly modify a DICOM instance received - * by Orthanc through any source (C-Store or Rest API) + * by Orthanc from any source (C-STORE or REST API) * * Signature of a callback function that is triggered whenever * Orthanc receives a new DICOM instance (through DICOM protocol or - * Rest API), and that answers a possibly modified version of the + * REST API), and that answers a possibly modified version of the * DICOM that should be stored in Orthanc. * - * This callback is called immediately after receiption: before + * This callback is called immediately after reception: before * transcoding and before filtering (FilterIncomingInstance). * * @param receivedDicomBuffer A buffer containing the received DICOM (input). * @param receivedDicomBufferSize The size of the received DICOM (input) * @param modifiedDicomBuffer A buffer containing the modified DICOM (output). - * This buffer will be freed by the Orthanc Core and must have - * been allocated by malloc in your plugin or by Orthanc core through - * a plugin method. - * @param modifiedDicomBufferSize The size of the modified DICOM (output) - * @return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs to accept the instance as is - * OrthancPluginReceivedInstanceCallbackResult_Modified to store the modified DICOM - * OrthancPluginReceivedInstanceCallbackResult_Discard to tell Orthanc to discard the instance + * This buffer will be freed by the Orthanc core and must have been allocated + * using OrthancPluginCreateMemoryBuffer64(). + * @return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs to accept the instance as is, + * OrthancPluginReceivedInstanceCallbackResult_Modified to store the modified DICOM, + * OrthancPluginReceivedInstanceCallbackResult_Discard to tell Orthanc to discard the instance. * @ingroup Callback **/ typedef OrthancPluginReceivedInstanceCallbackResult (*OrthancPluginReceivedInstanceCallback) ( + OrthancPluginMemoryBuffer64* modifiedDicomBuffer, const void* receivedDicomBuffer, - uint64_t receivedDicomBufferSize, - void** modifiedDicomBuffer, - uint64_t* modifiedDicomBufferSize - ); + uint64_t receivedDicomBufferSize); typedef struct @@ -7874,7 +7870,7 @@ /** * @brief Register a callback to possibly modify a DICOM instance received - * by Orthanc through any source (C-Store or Rest API) + * by Orthanc through any source (C-STORE or REST API) * * * @warning Your callback function will be called synchronously with diff -r 89f7d29a38c4 -r 95378de340d4 OrthancServer/Plugins/Samples/Sanitizer/Plugin.cpp --- a/OrthancServer/Plugins/Samples/Sanitizer/Plugin.cpp Wed Feb 23 06:36:06 2022 +0100 +++ b/OrthancServer/Plugins/Samples/Sanitizer/Plugin.cpp Wed Feb 23 06:36:29 2022 +0100 @@ -33,10 +33,9 @@ -OrthancPluginReceivedInstanceCallbackResult ReceivedInstanceCallback(const void* receivedDicomBuffer, - uint64_t receivedDicomBufferSize, - void** modifiedDicomBuffer, - uint64_t* modifiedDicomBufferSize) +OrthancPluginReceivedInstanceCallbackResult ReceivedInstanceCallback(OrthancPluginMemoryBuffer64* modifiedDicomBuffer, + const void* receivedDicomBuffer, + uint64_t receivedDicomBufferSize) { Orthanc::ParsedDicomFile dicom(receivedDicomBuffer, receivedDicomBufferSize); std::string institutionName = "My institution"; @@ -45,10 +44,9 @@ std::string modifiedDicom; dicom.SaveToMemoryBuffer(modifiedDicom); - - *modifiedDicomBuffer = malloc(modifiedDicom.size()); - *modifiedDicomBufferSize = modifiedDicom.size(); - memcpy(*modifiedDicomBuffer, modifiedDicom.c_str(), modifiedDicom.size()); + + OrthancPluginCreateMemoryBuffer64(OrthancPlugins::GetGlobalContext(), modifiedDicomBuffer, modifiedDicom.size()); + memcpy(modifiedDicomBuffer->data, modifiedDicom.c_str(), modifiedDicom.size()); return OrthancPluginReceivedInstanceCallbackResult_Modify; } diff -r 89f7d29a38c4 -r 95378de340d4 OrthancServer/Sources/ServerContext.cpp --- a/OrthancServer/Sources/ServerContext.cpp Wed Feb 23 06:36:06 2022 +0100 +++ b/OrthancServer/Sources/ServerContext.cpp Wed Feb 23 06:36:29 2022 +0100 @@ -687,34 +687,50 @@ StoreInstanceMode mode) { DicomInstanceToStore* dicom = &receivedDicom; + + // WARNING: The scope of "modifiedBuffer" and "modifiedDicom" must + // be the same as that of "dicom" + MallocMemoryBuffer modifiedBuffer; std::unique_ptr modifiedDicom; - std::unique_ptr raii(new MallocMemoryBuffer); - #if ORTHANC_ENABLE_PLUGINS == 1 if (HasPlugins()) { - void* modifiedDicomBuffer = NULL; - size_t modifiedDicomBufferSize = 0; + // New in Orthanc 1.10.0 - bool store = GetPlugins().ApplyReceivedInstanceCallbacks(receivedDicom.GetBufferData(), - receivedDicom.GetBufferSize(), - &modifiedDicomBuffer, - modifiedDicomBufferSize); - raii->Assign(modifiedDicomBuffer, modifiedDicomBufferSize, ::free); + OrthancPluginReceivedInstanceCallbackResult action = GetPlugins().ApplyReceivedInstanceCallbacks( + modifiedBuffer, receivedDicom.GetBufferData(), receivedDicom.GetBufferSize()); - if (!store) + switch (action) { - StoreResult result; - result.SetStatus(StoreStatus_FilteredOut); - return result; - } + case OrthancPluginReceivedInstanceCallbackResult_Discard: + { + CLOG(INFO, PLUGINS) << "A plugin has discarded the instance in its ReceivedInstanceCallback"; + StoreResult result; + result.SetStatus(StoreStatus_FilteredOut); + return result; + } + + case OrthancPluginReceivedInstanceCallbackResult_KeepAsIs: + break; - if (modifiedDicomBufferSize > 0 && modifiedDicomBuffer != NULL) - { - modifiedDicom.reset(DicomInstanceToStore::CreateFromBuffer(modifiedDicomBuffer, modifiedDicomBufferSize)); - modifiedDicom->SetOrigin(dicom->GetOrigin()); - dicom = modifiedDicom.get(); + case OrthancPluginReceivedInstanceCallbackResult_Modify: + if (modifiedBuffer.GetSize() > 0 && + modifiedBuffer.GetData() != NULL) + { + CLOG(INFO, PLUGINS) << "A plugin has modified the instance in its ReceivedInstanceCallback"; + modifiedDicom.reset(DicomInstanceToStore::CreateFromBuffer(modifiedBuffer.GetData(), modifiedBuffer.GetSize())); + modifiedDicom->SetOrigin(dicom->GetOrigin()); + dicom = modifiedDicom.get(); + } + else + { + throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback plugin is not returning a modified buffer while it has modified the instance"); + } + break; + + default: + throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback has returned an invalid value"); } } #endif