PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
association.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 <algorithm>
15#include <sstream>
16#include <stdexcept>
17
18namespace kcenon::pacs::network {
19
20// Use standardized error_info from kcenon::pacs::core::result.hpp
29
30// =============================================================================
31// rejection_info Implementation
32// =============================================================================
33
35 std::ostringstream oss;
36 oss << "Association rejected: ";
37
39 oss << "permanent, ";
40 } else {
41 oss << "transient, ";
42 }
43
44 switch (static_cast<reject_source>(source)) {
46 oss << "source=service-user, ";
47 switch (static_cast<reject_reason_user>(reason)) {
49 oss << "reason=no reason given";
50 break;
52 oss << "reason=application context not supported";
53 break;
55 oss << "reason=calling AE title not recognized";
56 break;
58 oss << "reason=called AE title not recognized";
59 break;
60 default:
61 oss << "reason=unknown (" << static_cast<int>(reason) << ")";
62 }
63 break;
65 oss << "source=service-provider (ACSE), ";
66 switch (static_cast<reject_reason_provider_acse>(reason)) {
68 oss << "reason=no reason given";
69 break;
71 oss << "reason=protocol version not supported";
72 break;
73 default:
74 oss << "reason=unknown (" << static_cast<int>(reason) << ")";
75 }
76 break;
78 oss << "source=service-provider (Presentation), ";
79 switch (static_cast<reject_reason_provider_presentation>(reason)) {
81 oss << "reason=temporary congestion";
82 break;
84 oss << "reason=local limit exceeded";
85 break;
86 default:
87 oss << "reason=unknown (" << static_cast<int>(reason) << ")";
88 }
89 break;
90 default:
91 oss << "source=unknown (" << static_cast<int>(source) << ")";
92 }
93
94 description = oss.str();
95}
96
97// =============================================================================
98// association Implementation - Construction/Destruction
99// =============================================================================
100
101association::association() = default;
102
104 std::lock_guard<std::mutex> lock(other.mutex_);
105 state_ = other.state_;
106 calling_ae_ = std::move(other.calling_ae_);
107 called_ae_ = std::move(other.called_ae_);
108 our_ae_ = std::move(other.our_ae_);
109 max_pdu_size_ = other.max_pdu_size_;
110 our_implementation_class_ = std::move(other.our_implementation_class_);
111 our_implementation_version_ = std::move(other.our_implementation_version_);
112 remote_implementation_class_ = std::move(other.remote_implementation_class_);
113 remote_implementation_version_ = std::move(other.remote_implementation_version_);
114 proposed_contexts_ = std::move(other.proposed_contexts_);
115 accepted_contexts_ = std::move(other.accepted_contexts_);
116 abstract_syntax_to_context_ = std::move(other.abstract_syntax_to_context_);
117 context_to_transfer_syntax_ = std::move(other.context_to_transfer_syntax_);
118 rejection_info_ = std::move(other.rejection_info_);
119 abort_source_ = other.abort_source_;
120 abort_reason_ = other.abort_reason_;
121 is_scu_ = other.is_scu_;
122 peer_ = other.peer_;
123 incoming_queue_ = std::move(other.incoming_queue_);
124 other.incoming_queue_ = std::make_unique<message_queue_type>();
125
126 other.state_ = association_state::idle;
127 other.peer_ = nullptr;
128
129 if (peer_) {
130 peer_->update_peer(&other, this);
131 }
132}
133
135 if (this != &other) {
136 std::scoped_lock lock(mutex_, other.mutex_);
137 state_ = other.state_;
138 calling_ae_ = std::move(other.calling_ae_);
139 called_ae_ = std::move(other.called_ae_);
140 our_ae_ = std::move(other.our_ae_);
141 max_pdu_size_ = other.max_pdu_size_;
142 our_implementation_class_ = std::move(other.our_implementation_class_);
143 our_implementation_version_ = std::move(other.our_implementation_version_);
144 remote_implementation_class_ = std::move(other.remote_implementation_class_);
145 remote_implementation_version_ = std::move(other.remote_implementation_version_);
146 proposed_contexts_ = std::move(other.proposed_contexts_);
147 accepted_contexts_ = std::move(other.accepted_contexts_);
148 abstract_syntax_to_context_ = std::move(other.abstract_syntax_to_context_);
149 context_to_transfer_syntax_ = std::move(other.context_to_transfer_syntax_);
150 rejection_info_ = std::move(other.rejection_info_);
151 abort_source_ = other.abort_source_;
152 abort_reason_ = other.abort_reason_;
153 is_scu_ = other.is_scu_;
154 peer_ = other.peer_;
155 incoming_queue_ = std::move(other.incoming_queue_);
156 other.incoming_queue_ = std::make_unique<message_queue_type>();
157
158 other.state_ = association_state::idle;
159 other.peer_ = nullptr;
160
161 if (peer_) {
162 peer_->update_peer(&other, this);
163 }
164 }
165 return *this;
166}
167
169 std::lock_guard<std::mutex> lock(mutex_);
171 // Abort silently on destruction
173 }
174}
175
176// =============================================================================
177// Factory Methods
178// =============================================================================
179
181 const std::string& host,
182 uint16_t port,
183 const association_config& config,
184 duration /*timeout*/) {
185
186 association assoc;
187 assoc.is_scu_ = true;
188 assoc.calling_ae_ = config.calling_ae_title;
189 assoc.called_ae_ = config.called_ae_title;
190 assoc.our_ae_ = config.calling_ae_title;
191 assoc.max_pdu_size_ = config.max_pdu_length;
194
195 // Copy proposed contexts
196 for (const auto& pc : config.proposed_contexts) {
197 assoc.proposed_contexts_.push_back(pc);
198 }
199
200 // Transition to awaiting state
202
203 // Check for in-memory server (Test Hook)
204 auto* server = dicom_server::get_server_on_port(port);
205 if (server) {
206 auto rq = assoc.build_associate_rq();
207 auto result = server->simulate_association_request(rq, &assoc);
208 if (result.is_ok()) {
209 if (assoc.process_associate_ac(result.value())) {
210 return assoc;
211 } else {
212 return error_info{no_acceptable_context, "Association negotiation failed", "network"};
213 }
214 } else {
215 return result.error();
216 }
217 }
218
219 // Note: Actual network connection should be handled by network_system
220 // This implementation prepares the association for PDU exchange
221 (void)host; // Will be used with network_system integration
222 (void)port;
223
224 return assoc;
225}
226
228 const associate_rq& rq,
229 const scp_config& config) {
230
231 association assoc;
232 assoc.is_scu_ = false;
233 assoc.calling_ae_ = rq.calling_ae_title;
234 assoc.called_ae_ = rq.called_ae_title;
235 assoc.our_ae_ = config.ae_title;
236 assoc.max_pdu_size_ = (std::min)(config.max_pdu_length, rq.user_info.max_pdu_length);
241
242 // Negotiate presentation contexts
243 assoc.negotiate_contexts(rq, config);
244
245 // Build lookup maps
246 assoc.build_context_map();
247
248 // Establish association if at least one context was accepted
249 // Note: For SCP, TCP connection is already established when accept() is called,
250 // so we directly set state to established (bypassing state machine)
251 bool has_accepted = std::any_of(
252 assoc.accepted_contexts_.begin(),
253 assoc.accepted_contexts_.end(),
254 [](const auto& ctx) { return ctx.is_accepted(); });
255
256 if (has_accepted) {
257 // SCP: A-ASSOCIATE-RQ received and accepted, go directly to established
259 } else {
260 // No acceptable contexts - will need to reject
262 }
263
264 return assoc;
265}
266
268 reject_result result,
269 uint8_t source,
270 uint8_t reason) {
271
272 return associate_rj{result, source, reason};
273}
274
275// =============================================================================
276// State Queries
277// =============================================================================
278
280 std::lock_guard<std::mutex> lock(mutex_);
281 return state_;
282}
283
284bool association::is_established() const noexcept {
285 std::lock_guard<std::mutex> lock(mutex_);
287}
288
289bool association::is_closed() const noexcept {
290 std::lock_guard<std::mutex> lock(mutex_);
294}
295
296// =============================================================================
297// Negotiated Parameters
298// =============================================================================
299
300std::string_view association::calling_ae() const noexcept {
301 std::lock_guard<std::mutex> lock(mutex_);
302 return calling_ae_;
303}
304
305std::string_view association::called_ae() const noexcept {
306 std::lock_guard<std::mutex> lock(mutex_);
307 return called_ae_;
308}
309
310uint32_t association::max_pdu_size() const noexcept {
311 std::lock_guard<std::mutex> lock(mutex_);
312 return max_pdu_size_;
313}
314
315std::string_view association::remote_implementation_class() const noexcept {
316 std::lock_guard<std::mutex> lock(mutex_);
318}
319
320std::string_view association::remote_implementation_version() const noexcept {
321 std::lock_guard<std::mutex> lock(mutex_);
323}
324
325// =============================================================================
326// Presentation Context Management
327// =============================================================================
328
330 std::lock_guard<std::mutex> lock(mutex_);
331 return abstract_syntax_to_context_.find(std::string(abstract_syntax)) !=
333}
334
335std::optional<uint8_t> association::accepted_context_id(
336 std::string_view abstract_syntax) const {
337
338 std::lock_guard<std::mutex> lock(mutex_);
339 auto it = abstract_syntax_to_context_.find(std::string(abstract_syntax));
340 if (it != abstract_syntax_to_context_.end()) {
341 return it->second;
342 }
343 return std::nullopt;
344}
345
347 uint8_t pc_id) const {
348
349 std::lock_guard<std::mutex> lock(mutex_);
350 auto it = context_to_transfer_syntax_.find(pc_id);
351 if (it == context_to_transfer_syntax_.end()) {
353 "Presentation context ID not found: " + std::to_string(pc_id),
354 "network"};
355 }
356 return it->second;
357}
358
359const std::vector<accepted_presentation_context>&
361 // Note: Not thread-safe for iteration, but const reference is OK
362 return accepted_contexts_;
363}
364
365// =============================================================================
366// DIMSE Operations
367// =============================================================================
368
370 uint8_t context_id,
371 const dimse::dimse_message& msg) {
372
373 std::lock_guard<std::mutex> lock(mutex_);
374
376 return error_info{invalid_association_state, "Cannot send DIMSE: association not established", "network"};
377 }
378
379 // Verify context exists
380 if (context_to_transfer_syntax_.find(context_id) ==
382 return error_info{kcenon::pacs::error_codes::dimse_error, "Invalid presentation context ID", "network"};
383 }
384
385 // Message encoding and network send would be handled by network_system
386 // For now, validate the message
387 if (!msg.is_valid()) {
388 return error_info{kcenon::pacs::error_codes::dimse_error, "Invalid DIMSE message", "network"};
389 }
390
391 // Placeholder for actual send implementation
392 (void)msg;
393
394 if (peer_) {
395 peer_->enqueue_message(context_id, msg);
396 return std::monostate{};
397 }
398
399 return std::monostate{};
400}
401
403 duration timeout) {
404
405 {
406 std::lock_guard<std::mutex> lock(mutex_);
408 return error_info{invalid_association_state, "Cannot receive DIMSE: association not established", "network"};
409 }
410 }
411
412 // Placeholder - actual receive would be implemented with network_system
413 // return error_info("Not implemented: requires network_system integration");
414
415 // Use lock-free queue with blocking wait
416 if (auto item = incoming_queue_->wait_dequeue(timeout)) {
417 return std::move(*item);
418 }
419
420 // Check if we were aborted/released while waiting
421 {
422 std::lock_guard<std::mutex> lock(mutex_);
424 return error_info{association_aborted, "Association aborted or released", "network"};
425 }
426 }
427
428 return error_info{receive_timeout, "Receive timeout", "network"};
429}
430
431// =============================================================================
432// PDU Access
433// =============================================================================
434
436 std::lock_guard<std::mutex> lock(mutex_);
437
438 associate_rq rq;
442
443 // Convert proposed contexts
444 for (const auto& pc : proposed_contexts_) {
445 rq.presentation_contexts.push_back(
446 presentation_context_rq{pc.id, pc.abstract_syntax, pc.transfer_syntaxes});
447 }
448
449 // User information
453
454 return rq;
455}
456
458 std::lock_guard<std::mutex> lock(mutex_);
459
460 associate_ac ac;
464
465 // Convert accepted contexts
466 for (const auto& ctx : accepted_contexts_) {
467 ac.presentation_contexts.push_back(
468 presentation_context_ac{ctx.id, ctx.result, ctx.transfer_syntax});
469 }
470
471 // User information
475
476 return ac;
477}
478
480 std::lock_guard<std::mutex> lock(mutex_);
481
483 return false;
484 }
485
486 // Store remote implementation info
489
490 // Update max PDU size to negotiated value
492
493 // Process accepted presentation contexts
494 accepted_contexts_.clear();
495 for (const auto& pc_ac : ac.presentation_contexts) {
496 // Find the corresponding proposed context
497 for (const auto& pc_rq : proposed_contexts_) {
498 if (pc_rq.id == pc_ac.id) {
500 pc_ac.id,
501 pc_rq.abstract_syntax,
502 pc_ac.transfer_syntax,
503 pc_ac.result
504 });
505 break;
506 }
507 }
508 }
509
510 // Build lookup maps
512
513 // Check if at least one context was accepted
514 bool has_accepted = std::any_of(
515 accepted_contexts_.begin(),
516 accepted_contexts_.end(),
517 [](const auto& ctx) { return ctx.is_accepted(); });
518
519 if (has_accepted) {
521 return true;
522 }
523
524 return false;
525}
526
528 std::lock_guard<std::mutex> lock(mutex_);
529
532}
533
534std::optional<rejection_info> association::get_rejection_info() const {
535 std::lock_guard<std::mutex> lock(mutex_);
536 return rejection_info_;
537}
538
539// =============================================================================
540// Lifecycle Management
541// =============================================================================
542
544 std::lock_guard<std::mutex> lock(mutex_);
545
547 return error_info{already_released, "Association already released", "network"};
548 }
549
551 return error_info{invalid_association_state, "Cannot release: association not established", "network"};
552 }
553
554 // Transition to awaiting release response
556
557 // Note: Actual A-RELEASE-RQ sending and A-RELEASE-RP receiving
558 // would be handled by network_system integration
559
560 // For now, simulate successful release
562
563 return std::monostate{};
564}
565
567 std::lock_guard<std::mutex> lock(mutex_);
568
571 }
572}
573
575 std::lock_guard<std::mutex> lock(mutex_);
576
579 }
580}
581
582void association::abort(uint8_t source, uint8_t reason) {
583 std::lock_guard<std::mutex> lock(mutex_);
584
585 abort_source_ = source;
586 abort_reason_ = reason;
588
589 // Wake up any waiters on the lock-free queue
590 incoming_queue_->notify_all();
591}
592
593void association::process_abort(const abort_source& source, const abort_reason& reason) {
594 std::lock_guard<std::mutex> lock(mutex_);
595
596 abort_source_ = static_cast<uint8_t>(source);
597 abort_reason_ = static_cast<uint8_t>(reason);
599
600 // Wake up any waiters on the lock-free queue
601 incoming_queue_->notify_all();
602}
603
605 std::lock_guard<std::mutex> lock(mutex_);
606 state_ = new_state;
607}
608
610 std::lock_guard<std::mutex> lock(mutex_);
611 peer_ = peer;
612}
613
615 // Lock-free enqueue with automatic notification
616 incoming_queue_->enqueue({context_id, std::move(msg)});
617}
618
620 std::lock_guard<std::mutex> lock(mutex_);
621 if (peer_ == old_peer) {
622 peer_ = new_peer;
623 }
624}
625
626// =============================================================================
627// Private Implementation
628// =============================================================================
629
631 // Define valid state transitions per PS3.8
632 switch (state_) {
634 return new_state == association_state::awaiting_associate_ac ||
636
638 return new_state == association_state::established ||
639 new_state == association_state::idle ||
640 new_state == association_state::aborted;
641
643 return new_state == association_state::established ||
644 new_state == association_state::idle ||
645 new_state == association_state::aborted;
646
648 return new_state == association_state::awaiting_release_rp ||
650 new_state == association_state::aborted;
651
653 return new_state == association_state::released ||
654 new_state == association_state::aborted;
655
657 return new_state == association_state::released ||
658 new_state == association_state::aborted;
659
662 return false; // Terminal states
663
664 default:
665 return false;
666 }
667}
668
670 if (can_transition_to(new_state)) {
671 state_ = new_state;
672 }
673}
674
678
679 for (const auto& ctx : accepted_contexts_) {
680 if (ctx.is_accepted()) {
681 abstract_syntax_to_context_[ctx.abstract_syntax] = ctx.id;
682
683 encoding::transfer_syntax ts{ctx.transfer_syntax};
684 if (ts.is_valid()) {
685 context_to_transfer_syntax_.emplace(ctx.id, std::move(ts));
686 }
687 }
688 }
689}
690
692 const associate_rq& rq,
693 const scp_config& config) {
694
695 accepted_contexts_.clear();
696
697 for (const auto& pc_rq : rq.presentation_contexts) {
698 // Check if we support the abstract syntax
699 bool supports_abstract = config.supported_abstract_syntaxes.empty() ||
700 std::find(config.supported_abstract_syntaxes.begin(),
701 config.supported_abstract_syntaxes.end(),
702 pc_rq.abstract_syntax) != config.supported_abstract_syntaxes.end();
703
704 if (!supports_abstract) {
706 pc_rq.id,
707 pc_rq.abstract_syntax,
708 "",
710 });
711 continue;
712 }
713
714 // Find first supported transfer syntax
715 std::string accepted_ts;
716 for (const auto& proposed_ts : pc_rq.transfer_syntaxes) {
717 bool supports_ts = config.supported_transfer_syntaxes.empty() ||
718 std::find(config.supported_transfer_syntaxes.begin(),
719 config.supported_transfer_syntaxes.end(),
720 proposed_ts) != config.supported_transfer_syntaxes.end();
721
722 if (supports_ts) {
723 accepted_ts = proposed_ts;
724 break;
725 }
726 }
727
728 if (accepted_ts.empty()) {
730 pc_rq.id,
731 pc_rq.abstract_syntax,
732 "",
734 });
735 } else {
737 pc_rq.id,
738 pc_rq.abstract_syntax,
739 accepted_ts,
741 });
742 }
743 }
744}
745
746} // namespace kcenon::pacs::network
DICOM Association management per PS3.8.
Represents a DICOM Transfer Syntax.
std::map< std::string, uint8_t > abstract_syntax_to_context_
Map from abstract syntax to accepted context ID.
std::string_view remote_implementation_version() const noexcept
Get remote implementation version name.
std::unique_ptr< message_queue_type > incoming_queue_
static association accept(const associate_rq &rq, const scp_config &config)
Accept an incoming SCP association.
std::string remote_implementation_class_
Remote implementation class UID.
std::vector< proposed_presentation_context > proposed_contexts_
Proposed presentation contexts (SCU)
uint8_t abort_reason_
Abort reason (if aborted)
bool process_associate_ac(const associate_ac &ac)
Process received A-ASSOCIATE-AC PDU.
void enqueue_message(uint8_t context_id, dimse::dimse_message msg)
Enqueue message from peer (for in-memory testing).
association()
Default constructor (creates idle association).
static Result< association > connect(const std::string &host, uint16_t port, const association_config &config, duration timeout=default_timeout)
Initiate an SCU association to a remote SCP.
std::optional< rejection_info > get_rejection_info() const
Get rejection info if association was rejected.
std::string called_ae_
Called AE Title.
std::string our_implementation_class_
Our implementation class UID.
std::string our_ae_
Our AE Title (may be calling or called depending on role)
~association()
Destructor (aborts if still established).
void process_release_rp()
Process received A-RELEASE-RP.
void build_context_map()
Build presentation context map from accepted contexts.
bool can_transition_to(association_state new_state) const
Validate state transition.
void set_state(association_state new_state)
Force state transition (for testing).
const std::vector< accepted_presentation_context > & accepted_contexts() const noexcept
Get all accepted presentation contexts.
bool is_established() const noexcept
Check if association is established and ready for DIMSE.
Result< std::monostate > send_dimse(uint8_t context_id, const dimse::dimse_message &msg)
Send a DIMSE message.
std::string_view calling_ae() const noexcept
Get calling AE title.
std::string_view called_ae() const noexcept
Get called AE title.
void update_peer(association *old_peer, association *new_peer)
Update peer pointer (for in-memory testing).
uint32_t max_pdu_size() const noexcept
Get negotiated maximum PDU size.
void process_release_rq()
Process received A-RELEASE-RQ.
bool is_scu_
Is this an SCU (true) or SCP (false)?
std::mutex mutex_
Thread safety mutex.
association & operator=(association &&other) noexcept
Move assignment operator.
associate_ac build_associate_ac() const
Build A-ASSOCIATE-AC PDU for sending.
std::string calling_ae_
Calling AE Title.
association_state state_
Current state.
associate_rq build_associate_rq() const
Build A-ASSOCIATE-RQ PDU for sending.
association_state state() const noexcept
Get current association state.
std::string our_implementation_version_
Our implementation version name.
Result< encoding::transfer_syntax > context_transfer_syntax(uint8_t pc_id) const
Get the transfer syntax for an accepted context.
void transition(association_state new_state)
Perform state transition.
void set_peer(association *peer)
Set peer association for in-memory testing.
std::chrono::milliseconds duration
std::map< uint8_t, encoding::transfer_syntax > context_to_transfer_syntax_
Map from context ID to transfer syntax.
Result< std::monostate > release(duration timeout=default_timeout)
Gracefully release the association.
association * peer_
Peer association for in-memory testing.
bool has_accepted_context(std::string_view abstract_syntax) const
Check if a presentation context for the abstract syntax was accepted.
uint8_t abort_source_
Abort source (if aborted)
Result< std::pair< uint8_t, dimse::dimse_message > > receive_dimse(duration timeout=default_timeout)
Receive a DIMSE message.
uint32_t max_pdu_size_
Negotiated maximum PDU size.
bool is_closed() const noexcept
Check if association has been released or aborted.
std::string remote_implementation_version_
Remote implementation version name.
void abort(uint8_t source=0, uint8_t reason=0)
Abort the association immediately.
std::vector< accepted_presentation_context > accepted_contexts_
Accepted presentation contexts.
void process_associate_rj(const associate_rj &rj)
Process received A-ASSOCIATE-RJ PDU.
void negotiate_contexts(const associate_rq &rq, const scp_config &config)
Negotiate presentation contexts for SCP.
static associate_rj reject(reject_result result, uint8_t source, uint8_t reason)
Reject an incoming association request.
std::optional< rejection_info > rejection_info_
Rejection information (if rejected)
std::string_view remote_implementation_class() const noexcept
Get remote implementation class UID.
void process_abort(const abort_source &source, const abort_reason &reason)
Process received A-ABORT PDU.
std::optional< uint8_t > accepted_context_id(std::string_view abstract_syntax) const
Get the presentation context ID for an abstract syntax.
static dicom_server * get_server_on_port(uint16_t port)
Get server instance listening on port (for in-memory testing).
auto is_valid() const noexcept -> bool
Check if the message is valid.
Multi-threaded DICOM server for handling multiple associations.
constexpr int no_acceptable_context
Definition result.h:103
constexpr int association_aborted
Definition result.h:89
constexpr int receive_timeout
Definition result.h:98
constexpr int release_failed
Definition result.h:104
constexpr int dimse_error
Definition result.h:90
constexpr int invalid_association_state
Definition result.h:101
constexpr int association_rejected
Definition result.h:88
constexpr int already_released
Definition result.h:105
reject_result
Reject result values.
Definition pdu_types.h:92
@ rejected_permanent
Rejected-permanent.
@ abstract_syntax
Abstract Syntax Sub-item.
constexpr const char * DICOM_APPLICATION_CONTEXT
Default DICOM Application Context Name (PS3.7)
Definition pdu_types.h:267
reject_reason_provider_acse
Reject reason values when source is service-provider (ACSE).
Definition pdu_types.h:119
@ protocol_version_not_supported
Protocol-version not supported.
abort_reason
Abort reason values when source is service-provider.
Definition pdu_types.h:79
reject_source
Reject source values.
Definition pdu_types.h:100
@ service_provider_acse
DICOM UL service-provider (ACSE)
@ service_user
DICOM UL service-user.
@ service_provider_presentation
DICOM UL service-provider (Presentation)
abort_source
Abort source values.
Definition pdu_types.h:70
reject_reason_provider_presentation
Reject reason values when source is service-provider (Presentation).
Definition pdu_types.h:127
@ abstract_syntax_not_supported
Abstract-syntax-not-supported.
@ transfer_syntaxes_not_supported
Transfer-syntaxes-not-supported.
association_state
DICOM Association state machine states per PS3.8.
Definition association.h:70
@ released
Association gracefully released.
@ awaiting_release_rp
Sta7: Awaiting A-RELEASE response (initiator)
@ awaiting_associate_ac
Sta5: Awaiting A-ASSOCIATE response (SCU)
@ established
Sta6: Association established, ready for DIMSE.
@ aborted
Association aborted (error condition)
@ awaiting_release_rq
Sta8: Awaiting potential A-RELEASE request.
@ awaiting_associate_rq
Sta2: Awaiting A-ASSOCIATE request (SCP)
@ idle
Sta1: No TCP connection, waiting for transport.
reject_reason_user
Reject reason values when source is service-user.
Definition pdu_types.h:109
@ called_ae_not_recognized
Called-AE-title not recognized.
@ application_context_not_supported
Application-context-name not supported.
@ calling_ae_not_recognized
Calling-AE-title not recognized.
kcenon::common::error_info error_info
Error information type.
Definition result.h:40
Transfer Syntax UIDs.
Definition main.cpp:78
Accepted presentation context after negotiation.
A-ASSOCIATE-AC PDU data.
Definition pdu_types.h:218
std::string calling_ae_title
Calling AE Title (16 chars max)
Definition pdu_types.h:220
user_information user_info
User Information.
Definition pdu_types.h:223
std::string called_ae_title
Called AE Title (16 chars max)
Definition pdu_types.h:219
std::string application_context
Application Context Name UID.
Definition pdu_types.h:221
std::vector< presentation_context_ac > presentation_contexts
Presentation Contexts.
Definition pdu_types.h:222
A-ASSOCIATE-RJ PDU data.
Definition pdu_types.h:231
uint8_t reason
Reason/Diagnostic.
Definition pdu_types.h:234
reject_result result
Result (1=permanent, 2=transient)
Definition pdu_types.h:232
A-ASSOCIATE-RQ PDU data.
Definition pdu_types.h:205
std::string called_ae_title
Called AE Title (16 chars max)
Definition pdu_types.h:206
std::string application_context
Application Context Name UID.
Definition pdu_types.h:208
user_information user_info
User Information.
Definition pdu_types.h:210
std::string calling_ae_title
Calling AE Title (16 chars max)
Definition pdu_types.h:207
std::vector< presentation_context_rq > presentation_contexts
Presentation Contexts.
Definition pdu_types.h:209
Configuration for SCU association request.
std::string called_ae_title
Remote AE Title (16 chars max)
std::string calling_ae_title
Our AE Title (16 chars max)
std::vector< proposed_presentation_context > proposed_contexts
Presentation Context for A-ASSOCIATE-AC.
Definition pdu_types.h:165
Presentation Context for A-ASSOCIATE-RQ.
Definition pdu_types.h:149
Information about an association rejection.
Configuration for SCP to accept associations.
std::string ae_title
Our AE Title.
std::vector< std::string > supported_abstract_syntaxes
std::vector< std::string > supported_transfer_syntaxes
std::string implementation_class_uid
Implementation Class UID.
Definition pdu_types.h:195
std::string implementation_version_name
Implementation Version Name (optional)
Definition pdu_types.h:196
uint32_t max_pdu_length
Maximum Length of P-DATA-TF PDUs.
Definition pdu_types.h:194