PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
network_adapter.cpp
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
13
14#include <kcenon/network/facade/tcp_facade.h>
15
16#include <filesystem>
17#include <future>
18#include <stdexcept>
19
21
22// =============================================================================
23// Server Creation
24// =============================================================================
25
26std::unique_ptr<network::dicom_server>
28 const tls_config& tls_cfg) {
29 // Validate configuration
30 if (config.ae_title.empty()) {
31 return nullptr;
32 }
33
34 if (config.port == 0) {
35 return nullptr;
36 }
37
38 // Validate TLS configuration if enabled
39 if (tls_cfg.enabled && !tls_cfg.is_valid()) {
40 return nullptr;
41 }
42
43 // Create DICOM server with the provided configuration
44 // The dicom_server internally uses network_system for TCP operations
45 return std::make_unique<network::dicom_server>(config);
46}
47
48// =============================================================================
49// Client Connection
50// =============================================================================
51
54 // Validate configuration
55 if (config.host.empty()) {
56 return Result<session_ptr>(error_info("Connection failed: empty host"));
57 }
58
59 if (config.port == 0) {
60 return Result<session_ptr>(error_info("Connection failed: invalid port"));
61 }
62
63 // Validate TLS configuration if enabled
64 if (config.tls.enabled && !config.tls.is_valid()) {
65 return Result<session_ptr>(error_info("Connection failed: invalid TLS configuration"));
66 }
67
68 try {
69 // Create TCP client via tcp_facade
70 kcenon::network::facade::tcp_facade facade;
71 kcenon::network::facade::tcp_facade::client_config client_cfg;
72 client_cfg.host = config.host;
73 client_cfg.port = config.port;
74 client_cfg.client_id = "pacs_client";
75 client_cfg.timeout = config.timeout;
76 client_cfg.use_ssl = config.tls.enabled;
77 if (config.tls.enabled && !config.tls.ca_path.empty()) {
78 client_cfg.ca_cert_path = config.tls.ca_path.string();
79 }
80 client_cfg.verify_certificate = config.tls.verify_peer;
81
82 // Handle both old API (returns shared_ptr) and new API (returns Result<shared_ptr>)
83 auto client = [](auto raw) -> std::shared_ptr<kcenon::network::interfaces::i_protocol_client> {
84 if constexpr (requires { raw.is_err(); raw.value(); }) {
85 return raw.is_err() ? nullptr : std::move(raw.value());
86 } else {
87 return std::move(raw);
88 }
89 }(facade.create_client(client_cfg));
90 if (!client) {
91 return Result<session_ptr>(error_info("Connection failed: could not create client"));
92 }
93
94 // Set up promise/future for synchronous connection
95 std::promise<std::error_code> connect_promise;
96 auto connect_future = connect_promise.get_future();
97
98 // Use deprecated callbacks for synchronous connect pattern
99 // (observer pattern would be preferred for long-lived clients)
100#if defined(__clang__) || defined(__GNUC__)
101#pragma GCC diagnostic push
102#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
103#endif
104 client->set_connected_callback([&connect_promise]() {
105 connect_promise.set_value(std::error_code{});
106 });
107
108 client->set_error_callback([&connect_promise](std::error_code ec) {
109 try {
110 connect_promise.set_value(ec);
111 } catch (const std::future_error&) {
112 // Promise already satisfied
113 }
114 });
115#if defined(__clang__) || defined(__GNUC__)
116#pragma GCC diagnostic pop
117#endif
118
119 // Start connection
120 auto start_result = client->start(config.host, config.port);
121 if (start_result.is_err()) {
122 return Result<session_ptr>(error_info("Connection failed: unable to start client"));
123 }
124
125 // Wait for connection with timeout
126 auto status = connect_future.wait_for(config.timeout);
127 if (status == std::future_status::timeout) {
128 (void)client->stop();
129 return Result<session_ptr>(error_info("Connection failed: timeout"));
130 }
131
132 // Check connection result
133 auto ec = connect_future.get();
134 if (ec) {
135 (void)client->stop();
136 return Result<session_ptr>(error_info("Connection failed: " + ec.message()));
137 }
138
139 // Connection successful but client-based session wrapping
140 // is not yet fully implemented for the public API
141 return Result<session_ptr>(error_info("Connection not yet fully implemented"));
142
143 } catch (const std::exception& e) {
144 return Result<session_ptr>(
145 error_info(std::string("Connection failed: ") + e.what()));
146 }
147}
148
150network_adapter::connect(const std::string& host,
151 uint16_t port,
152 std::chrono::milliseconds timeout) {
153 connection_config config{host, port};
154 config.timeout = timeout;
155 return connect(config);
156}
157
158// =============================================================================
159// TLS Configuration
160// =============================================================================
161
164 if (!config.enabled) {
165 return Result<std::monostate>(std::monostate{});
166 }
167
168 // Validate certificate path
169 if (!std::filesystem::exists(config.cert_path)) {
171 "TLS configuration error: certificate file not found: " +
172 config.cert_path.string()));
173 }
174
175 // Validate key path
176 if (!std::filesystem::exists(config.key_path)) {
178 "TLS configuration error: key file not found: " +
179 config.key_path.string()));
180 }
181
182 // Validate CA path if specified
183 if (!config.ca_path.empty() && !std::filesystem::exists(config.ca_path)) {
185 "TLS configuration error: CA certificate file not found: " +
186 config.ca_path.string()));
187 }
188
189 // TLS version validation
193 "TLS configuration error: unsupported TLS version"));
194 }
195
196 return Result<std::monostate>(std::monostate{});
197}
198
199// =============================================================================
200// Session Wrapping
201// =============================================================================
202
205 std::shared_ptr<network_system::session::messaging_session> session) {
206 if (!session) {
207 return nullptr;
208 }
209 return std::make_shared<dicom_session>(std::move(session));
210}
211
214 std::shared_ptr<network_system::session::secure_session> session) {
215 if (!session) {
216 return nullptr;
217 }
218 return std::make_shared<dicom_session>(std::move(session));
219}
220
223 std::shared_ptr<kcenon::network::interfaces::i_session> session) {
224 if (!session) {
225 return nullptr;
226 }
227 return std::make_shared<dicom_session>(std::move(session));
228}
229
230} // namespace kcenon::pacs::integration
Simple result type for error handling when common_system is unavailable.
static Result< std::monostate > configure_tls(const tls_config &config)
static std::unique_ptr< network::dicom_server > create_server(const network::server_config &config, const tls_config &tls_cfg={})
Create a DICOM server using network_system.
std::shared_ptr< dicom_session > session_ptr
Session pointer type.
static session_ptr wrap_session(std::shared_ptr< network_system::session::messaging_session > session)
Wrap a network_system session for DICOM communication.
static Result< session_ptr > connect(const connection_config &config)
Multi-threaded DICOM server for handling multiple associations.
DICOM session wrapper for network_system sessions.
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
Adapter for integrating network_system for DICOM protocol.
Configuration for client connections.
std::chrono::milliseconds timeout
Connection timeout.
tls_config tls
TLS configuration (optional)
Configuration for TLS/SSL secure transport.
bool enabled
Enable TLS for connections.
enum kcenon::pacs::integration::tls_config::tls_version min_version
bool is_valid() const noexcept
Check if TLS configuration is valid.
std::filesystem::path cert_path
Path to certificate file (PEM format)
std::filesystem::path ca_path
Path to CA certificate file for verification (optional)
bool verify_peer
Verify peer certificate.
std::filesystem::path key_path
Path to private key file (PEM format)
uint16_t port
Port to listen on (default: 11112, standard alternate DICOM port)
std::string ae_title
Application Entity Title for this server (16 chars max)