PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
dicom_session.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
20#pragma once
21
23
24#include <chrono>
25#include <condition_variable>
26#include <cstdint>
27#include <functional>
28#include <memory>
29#include <mutex>
30#include <string>
31#include <variant>
32#include <vector>
33
34// KCENON_HAS_COMMON_SYSTEM is defined by CMake when common_system is available
35#ifndef KCENON_HAS_COMMON_SYSTEM
36#define KCENON_HAS_COMMON_SYSTEM 0
37#endif
38
39#if KCENON_HAS_COMMON_SYSTEM
40#include <kcenon/common/patterns/result.h>
41#endif
42
43// Forward declarations for kcenon::network types
45class messaging_session;
46class secure_session;
47} // namespace kcenon::network::session
48
50class i_session;
51} // namespace kcenon::network::interfaces
52
53// Legacy namespace aliases for backward compatibility
55using messaging_session = kcenon::network::session::messaging_session;
56using secure_session = kcenon::network::session::secure_session;
57} // namespace network_system::session
58
60
61// =============================================================================
62// Result Type and Error Info
63// =============================================================================
64
65#if KCENON_HAS_COMMON_SYSTEM
66template <typename T>
68
69using error_info = kcenon::common::error_info;
70#else
74struct error_info {
75 int code = -1;
76 std::string message;
77 std::string module;
78
79 error_info() = default;
80 error_info(const std::string& msg) : message(msg) {}
81 error_info(int c, const std::string& msg, const std::string& mod = "")
82 : code(c), message(msg), module(mod) {}
83};
84
88template <typename T>
89class Result {
90public:
91 Result(T value) : data_(std::move(value)), has_value_(true) {}
92 Result(const error_info& err) : error_(err), has_value_(false) {}
93
94 [[nodiscard]] bool is_ok() const noexcept { return has_value_; }
95 [[nodiscard]] bool is_err() const noexcept { return !has_value_; }
96 [[nodiscard]] T& value() & { return data_; }
97 [[nodiscard]] const T& value() const& { return data_; }
98 [[nodiscard]] T&& value() && { return std::move(data_); }
99 [[nodiscard]] const error_info& error() const { return error_; }
100
101private:
102 T data_{};
105};
106#endif
107
108// =============================================================================
109// PDU Receive Result
110// =============================================================================
111
116struct pdu_data {
118 std::vector<uint8_t> payload;
119
120 pdu_data() : type(network::pdu_type::abort) {}
121 pdu_data(network::pdu_type t, std::vector<uint8_t> p)
122 : type(t), payload(std::move(p)) {}
123};
124
125// =============================================================================
126// DICOM Session Class
127// =============================================================================
128
172class dicom_session : public std::enable_shared_from_this<dicom_session> {
173public:
174 // ─────────────────────────────────────────────────────
175 // Type Aliases
176 // ─────────────────────────────────────────────────────
177
178 using clock = std::chrono::steady_clock;
179 using duration = std::chrono::milliseconds;
180 using time_point = clock::time_point;
181
183 static constexpr duration default_timeout{30000}; // 30 seconds
184
186 static constexpr size_t pdu_header_size = 6;
187
189 static constexpr size_t max_pdu_payload_size = 64 * 1024 * 1024; // 64MB
190
191 // ─────────────────────────────────────────────────────
192 // Construction / Destruction
193 // ─────────────────────────────────────────────────────
194
199 explicit dicom_session(
200 std::shared_ptr<network_system::session::messaging_session> session);
201
206 explicit dicom_session(
207 std::shared_ptr<network_system::session::secure_session> session);
208
217 explicit dicom_session(
218 std::shared_ptr<kcenon::network::interfaces::i_session> session);
219
224
225 // Non-copyable
226 dicom_session(const dicom_session&) = delete;
228
229 // Movable
230 dicom_session(dicom_session&& other) noexcept;
231 dicom_session& operator=(dicom_session&& other) noexcept;
232
233 // ─────────────────────────────────────────────────────
234 // PDU Operations
235 // ─────────────────────────────────────────────────────
236
250 [[nodiscard]] Result<std::monostate> send_pdu(
252 const std::vector<uint8_t>& payload);
253
263 [[nodiscard]] Result<std::monostate> send_raw(
264 const std::vector<uint8_t>& data);
265
277 [[nodiscard]] Result<pdu_data> receive_pdu(
278 duration timeout = default_timeout);
279
288 void set_pdu_callback(std::function<void(const pdu_data&)> callback);
289
293 void clear_pdu_callback();
294
295 // ─────────────────────────────────────────────────────
296 // External Event Injection (for i_session)
297 // ─────────────────────────────────────────────────────
298
307 void feed_data(const std::vector<uint8_t>& data);
308
316 void feed_error(std::error_code ec);
317
318 // ─────────────────────────────────────────────────────
319 // Connection State
320 // ─────────────────────────────────────────────────────
321
328 void close();
329
334 [[nodiscard]] bool is_open() const noexcept;
335
340 [[nodiscard]] std::string remote_address() const;
341
346 [[nodiscard]] std::string session_id() const;
347
352 [[nodiscard]] bool is_secure() const noexcept;
353
354 // ─────────────────────────────────────────────────────
355 // Error Handling
356 // ─────────────────────────────────────────────────────
357
362 void set_error_callback(std::function<void(std::error_code)> callback);
363
368 [[nodiscard]] std::error_code last_error() const noexcept;
369
370private:
371 // ─────────────────────────────────────────────────────
372 // Private Types
373 // ─────────────────────────────────────────────────────
374
376 using session_variant = std::variant<
377 std::shared_ptr<network_system::session::messaging_session>,
378 std::shared_ptr<network_system::session::secure_session>,
379 std::shared_ptr<kcenon::network::interfaces::i_session>>;
380
381 // ─────────────────────────────────────────────────────
382 // Private Methods
383 // ─────────────────────────────────────────────────────
384
386 void on_data_received(const std::vector<uint8_t>& data);
387
389 void on_error(std::error_code ec);
390
392 void process_buffer();
393
395 static std::vector<uint8_t> encode_pdu_header(
396 network::pdu_type type, uint32_t length);
397
399 static bool parse_pdu_header(
400 const std::vector<uint8_t>& buffer,
401 network::pdu_type& type,
402 uint32_t& length);
403
405 void send_data(std::vector<uint8_t>&& data);
406
407 // ─────────────────────────────────────────────────────
408 // Member Variables
409 // ─────────────────────────────────────────────────────
410
413
415 std::vector<uint8_t> receive_buffer_;
416
419
421 std::function<void(const pdu_data&)> pdu_callback_;
422
424 std::function<void(std::error_code)> error_callback_;
425
427 std::error_code last_error_;
428
430 bool closed_ = false;
431
433 mutable std::mutex mutex_;
434
436 std::condition_variable receive_cv_;
437};
438
439} // namespace kcenon::pacs::integration
Simple result type for error handling when common_system is unavailable.
const error_info & error() const
Result(const error_info &err)
DICOM session wrapper for network_system sessions.
Result< std::monostate > send_raw(const std::vector< uint8_t > &data)
Send raw PDU data (with header already included)
std::variant< std::shared_ptr< network_system::session::messaging_session >, std::shared_ptr< network_system::session::secure_session >, std::shared_ptr< kcenon::network::interfaces::i_session > > session_variant
Variant for holding session types (legacy + public interface)
void process_buffer()
Process buffered data for complete PDUs.
void set_pdu_callback(std::function< void(const pdu_data &)> callback)
Set callback for asynchronous PDU reception.
static constexpr duration default_timeout
Default receive timeout.
std::condition_variable receive_cv_
Condition variable for synchronous receive.
static constexpr size_t pdu_header_size
PDU header size per DICOM PS3.8.
bool is_open() const noexcept
Check if the session is open.
void feed_error(std::error_code ec)
Feed an error from external source.
Result< std::monostate > send_pdu(network::pdu_type type, const std::vector< uint8_t > &payload)
Send a complete DICOM PDU.
std::error_code last_error() const noexcept
Get the last error code.
bool is_secure() const noexcept
Check if this is a secure (TLS) session.
std::function< void(const pdu_data &)> pdu_callback_
PDU callback for async reception.
void clear_pdu_callback()
Clear the PDU callback.
std::vector< uint8_t > receive_buffer_
Receive buffer for PDU framing.
void feed_data(const std::vector< uint8_t > &data)
Feed received data from external source.
static bool parse_pdu_header(const std::vector< uint8_t > &buffer, network::pdu_type &type, uint32_t &length)
Parse PDU header from buffer.
void on_data_received(const std::vector< uint8_t > &data)
Handle incoming data from network.
session_variant session_
Underlying network session.
dicom_session(const dicom_session &)=delete
std::error_code last_error_
Last error code.
dicom_session(std::shared_ptr< network_system::session::messaging_session > session)
Construct a DICOM session wrapping a messaging_session.
dicom_session & operator=(const dicom_session &)=delete
std::function< void(std::error_code)> error_callback_
Error callback.
void set_error_callback(std::function< void(std::error_code)> callback)
Set callback for error events.
Result< pdu_data > receive_pdu(duration timeout=default_timeout)
Receive a complete DICOM PDU.
std::mutex mutex_
Mutex for thread safety.
static std::vector< uint8_t > encode_pdu_header(network::pdu_type type, uint32_t length)
Encode PDU header.
static constexpr size_t max_pdu_payload_size
Maximum PDU payload size (sanity check)
std::string remote_address() const
Get the remote peer address.
std::vector< pdu_data > received_pdus_
Queue of received complete PDUs.
std::string session_id() const
Get session identifier.
void on_error(std::error_code ec)
Handle connection errors.
void send_data(std::vector< uint8_t > &&data)
Send data through the underlying session.
~dicom_session()
Destructor (closes session if open)
std::shared_mutex mutex
Mutex for thread-safe access.
pdu_type
PDU (Protocol Data Unit) types as defined in DICOM PS3.8.
Definition pdu_types.h:25
kcenon::common::Result< T > Result
Result type alias for PACS operations.
Definition result.h:30
kcenon::common::error_info error_info
Error information type.
Definition result.h:40
kcenon::network::session::messaging_session messaging_session
kcenon::network::session::secure_session secure_session
Simple error info for fallback when common_system is unavailable.
error_info(int c, const std::string &msg, const std::string &mod="")
error_info(const std::string &msg)
Container for received PDU data.
std::vector< uint8_t > payload
PDU payload (excluding 6-byte header)
network::pdu_type type
PDU type from header.
pdu_data(network::pdu_type t, std::vector< uint8_t > p)