1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
Network association
===================
.. highlight:: c++
The connection between two DICOM peers is handled by `odil::Association`_ and `odil::AssociationParameters`_. The former encapsulates the connection itself (TCP/IP layer and DICOM layer) while the latter handles the various options that parameterize the association (AE titles, presentation contexts, authentication, etc.).
Establishing an association
---------------------------
An association will at least require to define the application entity titles (both local and remote) the presentation contexts (i.e. representation of the data) that are acceptable for the application. The following example shows how to create a simple `odil::AssociationParameters`_ object.
::
#include <odil/AssociationParameters.h>
#include <odil/registry.h>
odil::AssociationParameters
create_parameters()
{
std::vector<std::string> transfer_syntaxes{
odil::registry::ExplicitVRLittleEndian,
odil::registry::ExplicitVRLittleEndian
};
odil::AssociationParameters parameters;
parameters
.set_calling_ae_title("WORKSTATION")
.set_called_ae_title("SERVER")
.set_presentation_contexts({
{
odil::registry::Verification,
transfer_syntaxes,
odil::AssociationParameters::PresentationContext::Role::SCU
},
{
odil::registry::PatientRootQueryRetrieveInformationModelFind,
transfer_syntaxes,
odil::AssociationParameters::PresentationContext::Role::SCU
}
});
return parameters;
}
Note that the `odil::AssociationParameters`_ object uses parameter chaining. The objects passed to ``set_presentation_contexts`` are of type `odil::AssociationParameters::PresentationContext`_. In this example, the id of the presentation context is not specified: it is instead set to an special value by the constructor, and a valid id is then assigned in ``set_presentation_contexts``.
After setting the address and port of the remote peer, the association is established through the ``associate`` member function. Once established, the negotiated parameters (i.e. acceptable to both peers) may be obtained by the ``get_negotiated_parameters`` member function.
::
#include <odil/Association.h>
int main()
{
odil::Association association;
association.set_peer_host("www.dicomserver.co.uk");
association.set_peer_port(11112);
association.set_parameters(create_parameters());
association.associate();
auto const & contexts =
association.get_negotiated_parameters().get_presentation_contexts();
std::cout << "Presentation contexts (" << contexts.size() << ")\n";
for(auto const & context: contexts)
{
std::cout
<< "\t"
<< odil::registry::uids_dictionary.at(context.abstract_syntax).name
<< ": "
<< odil::registry::uids_dictionary.at(context.transfer_syntaxes[0]).name
<< ", "
<< (context.scu_role_support?"SCU":"")
<< ((context.scu_role_support & context.scp_role_support)?"/":"")
<< (context.scp_role_support?"SCP":"")
<< std::endl;
}
}
Receiving an association
------------------------
Receiving an association is performed by the ``receive_association`` member function. It will listen on the given IP address and TCP port and block until an acceptable association request is received or until an error occurs. By default all association requests are deemed acceptable, and the first transfer syntax of each presentation context is accepted. Errors (unacceptable association, low-level protocol error) will throw an exception. After acceptance, the association object contains the negotiated parameters:
::
#include <odil/Association.h>
int main()
{
odil::Association association;
association.receive_association(boost::asio::ip::tcp::v4(), 11112);
std::cout
<< "Received association from "
<< association.get_peer_host() << ":" << association.get_peer_port()
<< std::endl ;
auto const & contexts =
association.get_negotiated_parameters().get_presentation_contexts();
std::cout << "Presentation contexts (" << contexts.size() << ")\n";
for(auto const & context: contexts)
{
std::cout
<< "\t"
<< odil::registry::uids_dictionary.at(context.abstract_syntax).name
<< ": "
<< odil::registry::uids_dictionary.at(context.transfer_syntaxes[0]).name
<< ", "
<< (context.scu_role_support?"SCU":"")
<< ((context.scu_role_support & context.scp_role_support)?"/":"")
<< (context.scp_role_support?"SCP":"")
<< std::endl;
}
}
Optionnally, a callback which indicates whether the association request is acceptable or may be specified. If the request is acceptable, the callback must return the accepted parameters, otherwise it must throw an exception of type `odil::AssociationRejected`_. As an example, the default acceptation callback, which accepts the first transfer syntax for all abstract syntaxes, would be:
::
#include <odil/Association.h>
odil::AssociationParameters
acceptor(odil::AssociationParameters const & input)
{
odil::AssociationParameters output;
output.set_called_ae_title(input.get_called_ae_title());
output.set_calling_ae_title(input.get_calling_ae_title());
auto presentation_contexts = input.get_presentation_contexts();
for(auto & presentation_context: presentation_contexts)
{
presentation_context.transfer_syntaxes =
{ presentation_context.transfer_syntaxes[0] };
presentation_context.result =
odil::AssociationParameters::PresentationContext::Result::Acceptance;
}
output.set_presentation_contexts(presentation_contexts);
output.set_maximum_length(input.get_maximum_length());
return output;
}
.. _odil::Association: ../../_static/doxygen/classodil_1_1Association.html
.. _odil::AssociationParameters: ../../_static/doxygen/classodil_1_1AssociationParameters.html
.. _odil::AssociationParameters::PresentationContext: ../../_static/doxygen/structodil_1_1AssociationParameters_1_1PresentationContext.html
.. _odil::AssociationRejected: ../../_static/doxygen/structodil_1_1AssociationRejected.html
|