PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
dicom_server.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
19#ifndef PACS_NETWORK_DICOM_SERVER_HPP
20#define PACS_NETWORK_DICOM_SERVER_HPP
21
26
27#include <kcenon/thread/core/cancellation_token.h>
28
29#include <atomic>
30#include <chrono>
31#include <condition_variable>
32#include <functional>
33#include <memory>
34#include <mutex>
35#include <string>
36#include <unordered_map>
37#include <vector>
38
40class thread_pool_interface;
41} // namespace kcenon::pacs::integration
42
43namespace kcenon::pacs::network {
44
45// =============================================================================
46// Forward Declarations
47// =============================================================================
48
49class association_pool;
50
51// =============================================================================
52// DICOM Server Class
53// =============================================================================
54
98public:
99 // =========================================================================
100 // Type Aliases
101 // =========================================================================
102
103 using clock = std::chrono::steady_clock;
104 using duration = std::chrono::milliseconds;
105 using time_point = clock::time_point;
106
108 using association_callback = std::function<void(const association&)>;
109
111 using error_callback = std::function<void(const std::string&)>;
112
113 // =========================================================================
114 // Construction / Destruction
115 // =========================================================================
116
124 explicit dicom_server(const server_config& config);
125
135 const server_config& config,
136 std::shared_ptr<integration::thread_pool_interface> thread_pool);
137
142
143 // Non-copyable, non-movable (owns network resources)
144 dicom_server(const dicom_server&) = delete;
148
149 // =========================================================================
150 // Service Registration
151 // =========================================================================
152
163
168 [[nodiscard]] std::vector<std::string> supported_sop_classes() const;
169
170 // =========================================================================
171 // Lifecycle Management
172 // =========================================================================
173
181 [[nodiscard]] Result<std::monostate> start();
182
191 void stop(duration timeout = std::chrono::seconds{30});
192
199 void wait_for_shutdown();
200
201 // =========================================================================
202 // Status Queries
203 // =========================================================================
204
209 [[nodiscard]] bool is_running() const noexcept;
210
215 [[nodiscard]] size_t active_associations() const noexcept;
216
221 [[nodiscard]] server_statistics get_statistics() const;
222
227 [[nodiscard]] const server_config& config() const noexcept;
228
229 // =========================================================================
230 // Callbacks
231 // =========================================================================
232
238
244
249 void on_error(error_callback callback);
250
254 static dicom_server* get_server_on_port(uint16_t port);
255
260
261private:
262 // =========================================================================
263 // Private Implementation
264 // =========================================================================
265
268 uint64_t id;
272 std::string remote_address;
276 bool processing{false};
279 kcenon::thread::cancellation_token cancel_token;
280 };
281
282 // =========================================================================
283 // Private Methods
284 // =========================================================================
285
287 void handle_association(uint64_t session_id, association assoc);
288
290 void message_loop(association_info& info);
291
294 association& assoc,
295 uint8_t context_id,
296 const dimse::dimse_message& msg);
297
299 [[nodiscard]] bool validate_calling_ae(const std::string& calling_ae) const;
300
302 [[nodiscard]] bool validate_called_ae(const std::string& called_ae) const;
303
305 [[nodiscard]] services::scp_service* find_service(
306 const std::string& sop_class_uid) const;
307
310
312 void remove_association(uint64_t id);
313
315 void touch_association(uint64_t id);
316
318 void check_idle_timeouts();
319
321 [[nodiscard]] uint64_t next_association_id();
322
324 void report_error(const std::string& error);
325
326 // =========================================================================
327 // Member Variables
328 // =========================================================================
329
331 std::shared_ptr<integration::thread_pool_interface> thread_pool_;
332
335
337 std::vector<services::scp_service_ptr> services_;
338
340 std::unordered_map<std::string, services::scp_service*> sop_class_to_service_;
341
343 std::unordered_map<uint64_t, std::unique_ptr<association_info>> associations_;
344
347
349 std::atomic<uint64_t> association_id_counter_{0};
350
352 std::atomic<bool> running_{false};
353
355 std::unique_ptr<detail::accept_worker> accept_worker_;
356
358 mutable std::mutex associations_mutex_;
359
361 mutable std::mutex stats_mutex_;
362
364 mutable std::mutex services_mutex_;
365
367 std::condition_variable shutdown_cv_;
368
370 std::mutex shutdown_mutex_;
371
374
377
380
382 std::mutex callback_mutex_;
383};
384
385} // namespace kcenon::pacs::network
386
387#endif // PACS_NETWORK_DICOM_SERVER_HPP
Worker thread for accepting incoming DICOM connections.
DICOM Association management per PS3.8.
Result< std::monostate > dispatch_to_service(association &assoc, uint8_t context_id, const dimse::dimse_message &msg)
Dispatch message to appropriate service.
bool validate_called_ae(const std::string &called_ae) const
Validate called AE title.
uint64_t next_association_id()
Generate unique association ID.
std::unordered_map< std::string, services::scp_service * > sop_class_to_service_
Map from SOP Class UID to service.
std::mutex stats_mutex_
Statistics mutex.
void stop(duration timeout=std::chrono::seconds{30})
Stop the server gracefully.
std::chrono::steady_clock clock
void report_error(const std::string &error)
Report error through callback.
std::vector< std::string > supported_sop_classes() const
Get list of supported SOP Class UIDs.
void register_service(services::scp_service_ptr service)
Register an SCP service.
std::unique_ptr< detail::accept_worker > accept_worker_
Accept worker (replaces std::thread accept_thread_)
std::mutex services_mutex_
Service registry mutex.
services::scp_service * find_service(const std::string &sop_class_uid) const
Get service for SOP Class.
dicom_server & operator=(const dicom_server &)=delete
association_callback on_released_cb_
Association released callback.
bool validate_calling_ae(const std::string &calling_ae) const
Validate calling AE title.
Result< associate_ac > simulate_association_request(const associate_rq &rq, association *client_peer)
Simulate an incoming association request (for in-memory testing).
std::shared_ptr< integration::thread_pool_interface > thread_pool_
Thread pool for asynchronous task execution.
void on_error(error_callback callback)
Set callback for error events.
dicom_server(const dicom_server &)=delete
server_statistics get_statistics() const
Get server statistics.
void message_loop(association_info &info)
Process incoming DIMSE messages.
void remove_association(uint64_t id)
Remove association from pool.
void touch_association(uint64_t id)
Update association activity timestamp.
void wait_for_shutdown()
Wait for server shutdown.
std::function< void(const std::string &)> error_callback
Callback type for error events.
std::mutex associations_mutex_
Association mutex.
bool is_running() const noexcept
Check if server is running.
std::atomic< uint64_t > association_id_counter_
Association ID counter.
void on_association_released(association_callback callback)
Set callback for association released events.
std::vector< services::scp_service_ptr > services_
Registered SCP services.
std::mutex shutdown_mutex_
Shutdown mutex.
void handle_association(uint64_t session_id, association assoc)
Handle a single association (runs in worker thread)
dicom_server & operator=(dicom_server &&)=delete
dicom_server(const server_config &config)
Construct server with configuration.
static dicom_server * get_server_on_port(uint16_t port)
Get server instance listening on port (for in-memory testing).
std::unordered_map< uint64_t, std::unique_ptr< association_info > > associations_
Active associations.
size_t active_associations() const noexcept
Get number of active associations.
std::mutex callback_mutex_
Callback mutex.
error_callback on_error_cb_
Error callback.
std::atomic< bool > running_
Running flag.
~dicom_server()
Destructor (stops server if running)
association_callback on_established_cb_
Association established callback.
std::function< void(const association &)> association_callback
Callback type for association events.
void on_association_established(association_callback callback)
Set callback for association established events.
void check_idle_timeouts()
Check for idle timeout.
dicom_server(dicom_server &&)=delete
std::chrono::milliseconds duration
const server_config & config() const noexcept
Get server configuration.
server_config config_
Server configuration.
Result< std::monostate > start()
Start the server.
void add_association(association_info info)
Add association to pool.
std::condition_variable shutdown_cv_
Shutdown condition variable.
server_statistics stats_
Server statistics.
std::shared_ptr< scp_service > scp_service_ptr
Shared pointer type for SCP services.
Base class for DICOM SCP (Service Class Provider) services.
DICOM Server configuration structures.
A-ASSOCIATE-AC PDU data.
Definition pdu_types.h:218
A-ASSOCIATE-RQ PDU data.
Definition pdu_types.h:205
Internal association info for tracking.
kcenon::thread::cancellation_token cancel_token
Cancellation token for cooperative shutdown Allows graceful cancellation of message processing when s...
Statistics for server monitoring.