PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
kcenon::pacs::services::storage_scp Class Referencefinal

#include <storage_scp.h>

Inheritance diagram for kcenon::pacs::services::storage_scp:
Inheritance graph
Collaboration diagram for kcenon::pacs::services::storage_scp:
Collaboration graph

Public Member Functions

 storage_scp (std::shared_ptr< di::ILogger > logger=nullptr)
 Construct a Storage SCP with default configuration.
 
 storage_scp (const storage_scp_config &config, std::shared_ptr< di::ILogger > logger=nullptr)
 Construct a Storage SCP with custom configuration.
 
 ~storage_scp () override=default
 
void set_handler (storage_handler handler)
 Set the storage handler callback.
 
void set_pre_store_handler (pre_store_handler handler)
 Set the pre-store validation handler.
 
void set_post_store_handler (post_store_handler handler)
 
void set_audit_handler (std::shared_ptr< kcenon::pacs::security::atna_service_auditor > auditor)
 Set the ATNA audit handler for C-STORE operations.
 
std::vector< std::string > supported_sop_classes () const override
 Get supported SOP Class UIDs.
 
network::Result< std::monostate > handle_message (network::association &assoc, uint8_t context_id, const network::dimse::dimse_message &request) override
 Handle an incoming DIMSE message (C-STORE-RQ)
 
std::string_view service_name () const noexcept override
 Get the service name.
 
size_t images_received () const noexcept
 Get the number of images received since construction.
 
size_t bytes_received () const noexcept
 Get the total bytes received since construction.
 
void reset_statistics () noexcept
 Reset statistics counters to zero.
 
- Public Member Functions inherited from kcenon::pacs::services::scp_service
 scp_service (std::shared_ptr< di::ILogger > logger=nullptr)
 Construct SCP service with optional logger.
 
virtual ~scp_service ()=default
 
 scp_service (const scp_service &)=delete
 
scp_serviceoperator= (const scp_service &)=delete
 
 scp_service (scp_service &&)=default
 
scp_serviceoperator= (scp_service &&)=default
 
void set_logger (std::shared_ptr< di::ILogger > logger)
 Set the logger instance.
 
const std::shared_ptr< di::ILogger > & logger () const noexcept
 Get the current logger instance.
 
bool supports_sop_class (std::string_view sop_class_uid) const
 Check if this service supports a specific SOP Class.
 

Private Attributes

storage_scp_config config_
 Configuration.
 
storage_handler handler_
 Main storage handler.
 
pre_store_handler pre_store_handler_
 Pre-store validation handler.
 
post_store_handler post_store_handler_
 Post-store notification handler.
 
std::shared_ptr< kcenon::pacs::security::atna_service_auditorauditor_
 ATNA audit handler.
 
std::atomic< size_t > images_received_ {0}
 Statistics: number of images received.
 
std::atomic< size_t > bytes_received_ {0}
 Statistics: total bytes received.
 

Additional Inherited Members

- Protected Attributes inherited from kcenon::pacs::services::scp_service
std::shared_ptr< di::ILoggerlogger_
 Logger instance for service logging.
 

Detailed Description

Definition at line 161 of file storage_scp.h.

Constructor & Destructor Documentation

◆ storage_scp() [1/2]

kcenon::pacs::services::storage_scp::storage_scp ( std::shared_ptr< di::ILogger > logger = nullptr)
explicit

Construct a Storage SCP with default configuration.

Parameters
loggerLogger instance for service logging (nullptr uses null_logger)

Definition at line 26 of file storage_scp.cpp.

27 : scp_service(std::move(logger)) {}
const std::shared_ptr< di::ILogger > & logger() const noexcept
Get the current logger instance.
Definition scp_service.h:93
scp_service(std::shared_ptr< di::ILogger > logger=nullptr)
Construct SCP service with optional logger.
Definition scp_service.h:64

◆ storage_scp() [2/2]

kcenon::pacs::services::storage_scp::storage_scp ( const storage_scp_config & config,
std::shared_ptr< di::ILogger > logger = nullptr )
explicit

Construct a Storage SCP with custom configuration.

Parameters
configConfiguration options
loggerLogger instance for service logging (nullptr uses null_logger)

Definition at line 29 of file storage_scp.cpp.

31 : scp_service(std::move(logger)), config_(config) {}
storage_scp_config config_
Configuration.

◆ ~storage_scp()

kcenon::pacs::services::storage_scp::~storage_scp ( )
overridedefault

Member Function Documentation

◆ bytes_received()

size_t kcenon::pacs::services::storage_scp::bytes_received ( ) const
nodiscardnoexcept

Get the total bytes received since construction.

Returns
Total bytes of dataset data received

Definition at line 209 of file storage_scp.cpp.

209 {
210 return bytes_received_.load(std::memory_order_relaxed);
211}
std::atomic< size_t > bytes_received_
Statistics: total bytes received.

References bytes_received_.

◆ handle_message()

network::Result< std::monostate > kcenon::pacs::services::storage_scp::handle_message ( network::association & assoc,
uint8_t context_id,
const network::dimse::dimse_message & request )
nodiscardoverridevirtual

Handle an incoming DIMSE message (C-STORE-RQ)

Processes the C-STORE request:

  1. Validates the message is a C-STORE-RQ
  2. Extracts SOP Class/Instance UIDs
  3. Calls pre-store handler (if registered)
  4. Calls storage handler
  5. Sends C-STORE-RSP with appropriate status
Parameters
assocThe association on which the message was received
context_idThe presentation context ID for the message
requestThe incoming C-STORE-RQ message
Returns
Success or error

Implements kcenon::pacs::services::scp_service.

Definition at line 65 of file storage_scp.cpp.

68 {
69
70 using namespace network::dimse;
71
72 // Verify the message is a C-STORE request
73 if (request.command() != command_field::c_store_rq) {
76 "Expected C-STORE-RQ but received " +
77 std::string(to_string(request.command())));
78 }
79
80 // Extract SOP Class and Instance UIDs from the command set
81 const auto sop_class_uid = request.affected_sop_class_uid();
82 const auto sop_instance_uid = request.affected_sop_instance_uid();
83
84 // Verify the request has a dataset
85 if (!request.has_dataset()) {
86 auto response = make_c_store_rsp(
87 request.message_id(),
88 sop_class_uid,
89 sop_instance_uid,
90 static_cast<status_code>(storage_status::cannot_understand)
91 );
92 return assoc.send_dimse(context_id, response);
93 }
94
95 // Get dataset reference (already validated above)
96 const auto& dataset = request.dataset().value().get();
97
98 // Pre-store validation
99 if (pre_store_handler_ && !pre_store_handler_(dataset)) {
100 auto response = make_c_store_rsp(
101 request.message_id(),
102 sop_class_uid,
103 sop_instance_uid,
104 static_cast<status_code>(storage_status::cannot_understand)
105 );
106 return assoc.send_dimse(context_id, response);
107 }
108
109 // Determine storage status
110 storage_status status = storage_status::success;
111
112 if (handler_) {
113 // Call the registered storage handler
115 dataset,
116 std::string(assoc.calling_ae()),
117 sop_class_uid,
118 sop_instance_uid
119 );
120 }
121
122 // Update statistics and notify on success or warning
123 if (!is_failure(status)) {
124 images_received_.fetch_add(1, std::memory_order_relaxed);
125 // Estimate dataset size - use element count as approximation
126 // In production, this would use actual serialized size
127 bytes_received_.fetch_add(
128 dataset.size() * sizeof(uint32_t),
129 std::memory_order_relaxed
130 );
131
132 // Call post-store handler for cache invalidation and notifications
133 auto patient_id = dataset.get_string(core::tags::patient_id);
134 auto study_uid = dataset.get_string(core::tags::study_instance_uid);
135 auto series_uid = dataset.get_string(core::tags::series_instance_uid);
136
139 dataset,
140 patient_id,
141 study_uid,
142 series_uid,
143 sop_instance_uid
144 );
145 }
146
147 // Publish image received event
148 kcenon::common::get_event_bus().publish(
151 study_uid,
152 series_uid,
155 std::string(assoc.calling_ae()),
156 bytes_received_.load(std::memory_order_relaxed)
157 }
158 );
159 } else {
160 // Storage failed - publish failure event
161 auto patient_id = dataset.get_string(core::tags::patient_id);
162
163 kcenon::common::get_event_bus().publish(
167 std::string(assoc.calling_ae()),
168 static_cast<int>(status),
169 "C-STORE operation failed"
170 }
171 );
172 }
173
174 // Emit ATNA audit event
175 if (auditor_) {
176 auto audit_study_uid = dataset.get_string(core::tags::study_instance_uid);
177 auto audit_patient_id = dataset.get_string(core::tags::patient_id);
179 std::string(assoc.calling_ae()),
180 std::string(assoc.called_ae()),
181 audit_study_uid,
182 audit_patient_id,
183 !is_failure(status));
184 }
185
186 // Build and send the response
187 auto response = make_c_store_rsp(
188 request.message_id(),
189 sop_class_uid,
190 sop_instance_uid,
191 static_cast<status_code>(status)
192 );
193
194 return assoc.send_dimse(context_id, response);
195}
void audit_instance_stored(const std::string &source_ae, const std::string &dest_ae, const std::string &study_uid, const std::string &patient_id, bool success)
Audit a C-STORE (DICOM Instances Transferred) event.
std::shared_ptr< kcenon::pacs::security::atna_service_auditor > auditor_
ATNA audit handler.
storage_handler handler_
Main storage handler.
std::atomic< size_t > images_received_
Statistics: number of images received.
pre_store_handler pre_store_handler_
Pre-store validation handler.
post_store_handler post_store_handler_
Post-store notification handler.
constexpr dicom_tag patient_id
Patient ID.
constexpr dicom_tag sop_instance_uid
SOP Instance UID.
constexpr dicom_tag status
Status.
constexpr dicom_tag study_instance_uid
Study Instance UID.
constexpr dicom_tag sop_class_uid
SOP Class UID.
constexpr dicom_tag series_instance_uid
Series Instance UID.
constexpr int store_unexpected_command
Definition result.h:151
constexpr bool is_failure(storage_status status) noexcept
Check if the status indicates a failure.
@ success
Success - image stored successfully (0x0000)
@ cannot_understand
Failure: Cannot understand - processing failure (0xC000)
auto to_string(mpps_status status) -> std::string_view
Convert mpps_status to DICOM string representation.
Definition mpps_scp.h:60
VoidResult pacs_void_error(int code, const std::string &message, const std::string &details="")
Create a PACS void error result.
Definition result.h:249
Event published when an image is successfully received via C-STORE.
Definition events.h:108
Event published when a C-STORE operation fails.
Definition events.h:138

References kcenon::pacs::network::dimse::dimse_message::affected_sop_class_uid(), kcenon::pacs::network::dimse::dimse_message::affected_sop_instance_uid(), kcenon::pacs::security::atna_service_auditor::audit_instance_stored(), auditor_, bytes_received_, kcenon::pacs::network::association::called_ae(), kcenon::pacs::network::association::calling_ae(), kcenon::pacs::services::cannot_understand, kcenon::pacs::network::dimse::dimse_message::command(), kcenon::pacs::network::dimse::dimse_message::dataset(), handler_, kcenon::pacs::network::dimse::dimse_message::has_dataset(), images_received_, kcenon::pacs::services::is_failure(), kcenon::pacs::network::dimse::dimse_message::message_id(), kcenon::pacs::pacs_void_error(), kcenon::pacs::core::tags::patient_id, post_store_handler_, pre_store_handler_, kcenon::pacs::network::association::send_dimse(), kcenon::pacs::core::tags::series_instance_uid, kcenon::pacs::error_codes::store_unexpected_command, kcenon::pacs::core::tags::study_instance_uid, kcenon::pacs::services::success, and kcenon::pacs::services::to_string().

Here is the call graph for this function:

◆ images_received()

size_t kcenon::pacs::services::storage_scp::images_received ( ) const
nodiscardnoexcept

Get the number of images received since construction.

Returns
Count of successfully received images

Definition at line 205 of file storage_scp.cpp.

205 {
206 return images_received_.load(std::memory_order_relaxed);
207}

References images_received_.

◆ reset_statistics()

void kcenon::pacs::services::storage_scp::reset_statistics ( )
noexcept

Reset statistics counters to zero.

Definition at line 213 of file storage_scp.cpp.

213 {
214 images_received_.store(0, std::memory_order_relaxed);
215 bytes_received_.store(0, std::memory_order_relaxed);
216}

References bytes_received_, and images_received_.

◆ service_name()

std::string_view kcenon::pacs::services::storage_scp::service_name ( ) const
nodiscardoverridevirtualnoexcept

Get the service name.

Returns
"Storage SCP"

Implements kcenon::pacs::services::scp_service.

Definition at line 197 of file storage_scp.cpp.

197 {
198 return "Storage SCP";
199}

◆ set_audit_handler()

void kcenon::pacs::services::storage_scp::set_audit_handler ( std::shared_ptr< kcenon::pacs::security::atna_service_auditor > auditor)

Set the ATNA audit handler for C-STORE operations.

When set, audit events are emitted for each C-STORE operation (both success and failure).

Parameters
auditorShared pointer to an ATNA service auditor

Definition at line 49 of file storage_scp.cpp.

50 {
51 auditor_ = std::move(auditor);
52}

References auditor_.

◆ set_handler()

void kcenon::pacs::services::storage_scp::set_handler ( storage_handler handler)

Set the storage handler callback.

This handler is called for each received C-STORE request after pre-validation passes. It should perform the actual storage operation.

Parameters
handlerThe storage callback function

Definition at line 37 of file storage_scp.cpp.

37 {
38 handler_ = std::move(handler);
39}

References handler_.

◆ set_post_store_handler()

void kcenon::pacs::services::storage_scp::set_post_store_handler ( post_store_handler handler)

Definition at line 45 of file storage_scp.cpp.

45 {
46 post_store_handler_ = std::move(handler);
47}

References post_store_handler_.

Referenced by kcenon::pacs::client::routing_manager::attach_to_storage_scp(), and kcenon::pacs::client::routing_manager::detach_from_storage_scp().

Here is the caller graph for this function:

◆ set_pre_store_handler()

void kcenon::pacs::services::storage_scp::set_pre_store_handler ( pre_store_handler handler)

Set the pre-store validation handler.

This handler is called before the main storage handler to validate incoming datasets. Return false to reject the storage request.

Parameters
handlerThe pre-validation callback function

Definition at line 41 of file storage_scp.cpp.

41 {
42 pre_store_handler_ = std::move(handler);
43}

References pre_store_handler_.

◆ supported_sop_classes()

std::vector< std::string > kcenon::pacs::services::storage_scp::supported_sop_classes ( ) const
nodiscardoverridevirtual

Get supported SOP Class UIDs.

Returns the list of Storage SOP Classes this service accepts. If no specific classes are configured, returns all standard storage classes.

Returns
Vector of accepted SOP Class UIDs

Implements kcenon::pacs::services::scp_service.

Definition at line 58 of file storage_scp.cpp.

58 {
59 if (!config_.accepted_sop_classes.empty()) {
61 }
63}
std::vector< std::string > get_standard_storage_sop_classes()
Get a list of all standard Storage SOP Class UIDs.
std::vector< std::string > accepted_sop_classes
List of accepted SOP Class UIDs (empty = accept all standard storage classes)
Definition storage_scp.h:51

References kcenon::pacs::services::storage_scp_config::accepted_sop_classes, config_, and kcenon::pacs::services::get_standard_storage_sop_classes().

Here is the call graph for this function:

Member Data Documentation

◆ auditor_

std::shared_ptr<kcenon::pacs::security::atna_service_auditor> kcenon::pacs::services::storage_scp::auditor_
private

ATNA audit handler.

Definition at line 328 of file storage_scp.h.

Referenced by handle_message(), and set_audit_handler().

◆ bytes_received_

std::atomic<size_t> kcenon::pacs::services::storage_scp::bytes_received_ {0}
private

Statistics: total bytes received.

Definition at line 334 of file storage_scp.h.

334{0};

Referenced by bytes_received(), handle_message(), and reset_statistics().

◆ config_

storage_scp_config kcenon::pacs::services::storage_scp::config_
private

Configuration.

Definition at line 316 of file storage_scp.h.

Referenced by supported_sop_classes().

◆ handler_

storage_handler kcenon::pacs::services::storage_scp::handler_
private

Main storage handler.

Definition at line 319 of file storage_scp.h.

Referenced by handle_message(), and set_handler().

◆ images_received_

std::atomic<size_t> kcenon::pacs::services::storage_scp::images_received_ {0}
private

Statistics: number of images received.

Definition at line 331 of file storage_scp.h.

331{0};

Referenced by handle_message(), images_received(), and reset_statistics().

◆ post_store_handler_

post_store_handler kcenon::pacs::services::storage_scp::post_store_handler_
private

Post-store notification handler.

Definition at line 325 of file storage_scp.h.

Referenced by handle_message(), and set_post_store_handler().

◆ pre_store_handler_

pre_store_handler kcenon::pacs::services::storage_scp::pre_store_handler_
private

Pre-store validation handler.

Definition at line 322 of file storage_scp.h.

Referenced by handle_message(), and set_pre_store_handler().


The documentation for this class was generated from the following files: