1 /*=========================================================================
2 *
3 * Copyright Insight Software Consortium
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0.txt
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *=========================================================================*/
18 /*
19
20 This file contains the implementation for the classes for the AE Actions,
21 Association Establishment Related Actions (Table 9-6 of ps 3.8-2009).
22
23 Since each class is essentially a placeholder for a function pointer, I'm breaking with having
24 each class have its own file for the sake of brevity of the number of files.
25
26 */
27
28 #include "gdcmULActionAE.h"
29 #include "gdcmARTIMTimer.h"
30 #include "gdcmAAssociateRQPDU.h"
31 #include "gdcmAAssociateACPDU.h"
32 #include "gdcmAAssociateRJPDU.h"
33
34 #include <socket++/echo.h>//for setting up the local socket
35
36 namespace gdcm
37 {
38 namespace network
39 {
40
41 //Issue TRANSPORT CONNECT request primitive to local transport service.
PerformAction(Subject *,ULEvent &,ULConnection & inConnection,bool & outWaitingForEvent,EEventID & outRaisedEvent)42 EStateID ULActionAE1::PerformAction(Subject *, ULEvent& , ULConnection& inConnection,
43 bool& outWaitingForEvent, EEventID& outRaisedEvent){
44
45 //opening a local socket
46 outWaitingForEvent = false;
47 if (!inConnection.InitializeConnection())
48 {
49 outRaisedEvent = eEventDoesNotExist;
50 return eSta1Idle;
51 }
52 else
53 {
54 outRaisedEvent = eTransportConnConfirmLocal;
55 }
56 return eSta4LocalAssocDone;
57 }
58
59 //Send A-ASSOCIATE-RQ-PDU
PerformAction(Subject *,ULEvent &,ULConnection & inConnection,bool & outWaitingForEvent,EEventID & outRaisedEvent)60 EStateID ULActionAE2::PerformAction(Subject *, ULEvent& , ULConnection& inConnection,
61 bool& outWaitingForEvent, EEventID& outRaisedEvent)
62 {
63 AAssociateRQPDU thePDU;
64
65 thePDU.SetCallingAETitle( inConnection.GetConnectionInfo().GetCallingAETitle() );
66 thePDU.SetCalledAETitle( inConnection.GetConnectionInfo().GetCalledAETitle() );
67
68 //the presentation context is now defined when the connection is first
69 //desired to be established. The connection proposes these different
70 //presentation contexts. ideally, we could refine it further to a particular
71 //presentation context, but if the server supports many and we support many,
72 //then an arbitrary decision can be made.
73 std::vector<PresentationContextRQ> const & thePCS =
74 inConnection.GetPresentationContexts();
75
76 std::vector<PresentationContextRQ>::const_iterator itor;
77 for (itor = thePCS.begin(); itor < thePCS.end(); itor++)
78 {
79 thePDU.AddPresentationContext(*itor);
80 }
81
82 thePDU.Write(*inConnection.GetProtocol());
83 inConnection.GetProtocol()->flush();
84
85 outWaitingForEvent = true;
86 outRaisedEvent = eEventDoesNotExist;
87
88 return eSta5WaitRemoteAssoc;
89 }
90
91 //Issue A-ASSOCIATE confirmation (accept) primitive
92 // NOTE: A-ASSOCIATE is NOT A-ASSOCIATE-AC
93 // PS 3.7 / Annex D for A-ASSOCIATE definition
PerformAction(Subject *,ULEvent & inEvent,ULConnection & inConnection,bool & outWaitingForEvent,EEventID & outRaisedEvent)94 EStateID ULActionAE3::PerformAction(Subject *, ULEvent& inEvent, ULConnection& inConnection,
95 bool& outWaitingForEvent, EEventID& outRaisedEvent){
96
97
98 // Mark please check this junk:
99 assert(!inEvent.GetPDUs().empty());
100 AAssociateACPDU* acpdu;
101 acpdu = dynamic_cast<AAssociateACPDU*>(inEvent.GetPDUs()[0]);
102 assert( acpdu );
103 uint32_t maxpdu = acpdu->GetUserInformation().GetMaximumLengthSub().GetMaximumLength();
104 inConnection.SetMaxPDUSize(maxpdu);
105
106 // once again duplicate AAssociateACPDU vs ULConnection
107 for( unsigned int index = 0; index < acpdu->GetNumberOfPresentationContextAC(); index++ ){
108 PresentationContextAC const &pc = acpdu->GetPresentationContextAC(index);
109 inConnection.AddAcceptedPresentationContext(pc);
110 }
111
112 outWaitingForEvent = false;
113 outRaisedEvent = eEventDoesNotExist;//no event is raised,
114 //wait for the user to try to send some data.
115 return eSta6TransferReady;
116 }
117
118 //Issue A-ASSOCIATE confirmation (reject) primitive and close transport connection
PerformAction(Subject *,ULEvent &,ULConnection &,bool & outWaitingForEvent,EEventID & outRaisedEvent)119 EStateID ULActionAE4::PerformAction(Subject *, ULEvent& , ULConnection& ,
120 bool& outWaitingForEvent, EEventID& outRaisedEvent){
121
122 outWaitingForEvent = false;
123 outRaisedEvent = eASSOCIATE_RJPDUreceived;
124 return eSta1Idle;
125 }
126
127 //Issue Transport connection response primitive, start ARTIM timer
PerformAction(Subject *,ULEvent &,ULConnection & inConnection,bool & outWaitingForEvent,EEventID & outRaisedEvent)128 EStateID ULActionAE5::PerformAction(Subject *, ULEvent& , ULConnection& inConnection,
129 bool& outWaitingForEvent, EEventID& outRaisedEvent){
130
131 //issue response primitive; have to set that up
132 inConnection.GetTimer().Start();
133
134 outWaitingForEvent = false;
135 outRaisedEvent = eTransportConnConfirmLocal;
136 return eSta2Open;
137 }
138
139 //Stop ARTIM timer and if A-ASSOCIATE-RQ acceptable by service-provider:
140 //- issue A-ASSOCIATE indication primitive
141 //Next state: eSta3WaitLocalAssoc
142 //otherwise:
143 //- issue A-ASSOCIATE-RJ-PDU and start ARTIM timer
144 //Next state: eSta13AwaitingClose
PerformAction(Subject *,ULEvent & inEvent,ULConnection & inConnection,bool & outWaitingForEvent,EEventID & outRaisedEvent)145 EStateID ULActionAE6::PerformAction(Subject *, ULEvent& inEvent, ULConnection& inConnection,
146 bool& outWaitingForEvent, EEventID& outRaisedEvent){
147
148 // we are in a C-MOVE
149
150 inConnection.GetTimer().Stop();
151
152 //have to determine 'acceptability'
153 //this is more server side than client, so it's a bit empty now
154 //we have one server type, a store scp started on a cmove
155 //so, it's defined as acceptable.
156 bool acceptable = true;//for now, always accept
157 if (inEvent.GetPDUs().empty()){
158 acceptable = false; //can't accept an empty set of pdus.
159 //also, requrie little endian, not sure how to set that, but it should be here.
160 }
161 AAssociateRQPDU* rqpdu;
162 if (acceptable){
163 rqpdu = dynamic_cast<AAssociateRQPDU*>(inEvent.GetPDUs()[0]);
164 if (rqpdu == nullptr){
165 acceptable = false;
166 }
167 }
168 if (acceptable){
169 outWaitingForEvent = false;//not waiting, now want to get the
170 //sending of data underway. Have to get info now
171 outRaisedEvent = eAASSOCIATEresponseAccept;
172
173 TransferSyntaxSub ts1;
174 ts1.SetNameFromUID( UIDs::ImplicitVRLittleEndianDefaultTransferSyntaxforDICOM );
175
176 AAssociateACPDU acpdu;
177
178 assert( rqpdu->GetNumberOfPresentationContext() );
179 for( unsigned int index = 0; index < rqpdu->GetNumberOfPresentationContext(); index++ )
180 {
181 // FIXME / HARDCODED We only ever accept Little Endian
182 // FIXME we should check :
183 // rqpdu.GetAbstractSyntax() contains LittleEndian
184 PresentationContextAC pcac1;
185 PresentationContextRQ const &pc = rqpdu->GetPresentationContext(index);
186 //add the presentation context back into the connection,
187 //so later functions will know what's allowed on this connection
188 // BOGUS (MM):
189 //inConnection.AddAcceptedPresentationContext(pc);
190
191 const uint8_t id = pc.GetPresentationContextID();
192
193 std::vector<TransferSyntaxSub> const & tsSet = pc.GetTransferSyntaxes();
194 std::vector<TransferSyntaxSub>::const_iterator tsitor;
195 // PS 3.8 Table 9-18 PRESENTATION CONTEXT ITEM FIELDS
196 uint8_t result = 4; // transfer-syntaxes-not-supported (provider rejection)
197 for (tsitor = tsSet.begin(); tsitor < tsSet.end(); tsitor++)
198 {
199 //gdcmDebugMacro( "Checking: [" << tsitor->GetName() << "] vs [" << ts1.GetName() << "]" << std::endl );
200 if (strcmp(tsitor->GetName(), ts1.GetName()) == 0 )
201 {
202 result = 0; // 0 - acceptance
203 inConnection.SetCStoreTransferSyntax( ts1 );
204 pcac1.SetTransferSyntax( ts1 );
205 }
206 }
207 if( result )
208 {
209 gdcmWarningMacro( "Could not find Implicit or Explicit Little Endian in Response. Giving another try" );
210 // Okay little endian implicit was not found, this happen sometimes, for eg with DVTk, let's be nice and accept also Explicit
211 TransferSyntaxSub ts2;
212 ts2.SetNameFromUID( UIDs::ExplicitVRLittleEndian );
213 for (tsitor = tsSet.begin(); tsitor < tsSet.end(); tsitor++)
214 {
215 //gdcmDebugMacro( "Checking: [" << tsitor->GetName() << "] vs [" << ts1.GetName() << "]" << std::endl );
216 if (strcmp(tsitor->GetName(), ts2.GetName()) == 0 )
217 {
218 result = 0; // 0 - acceptance
219 inConnection.SetCStoreTransferSyntax( ts2 );
220 pcac1.SetTransferSyntax( ts2 );
221 }
222 }
223 }
224 if( result )
225 {
226 gdcmErrorMacro( "Could not find Implicit or Explicit Little Endian in Response. Giving up" );
227 }
228 pcac1.SetPresentationContextID( id );
229 pcac1.SetReason( result );
230 acpdu.AddPresentationContextAC( pcac1 );
231 }
232 assert( acpdu.GetNumberOfPresentationContextAC() );
233
234 // Init AE-Titles:
235 acpdu.InitFromRQ( *rqpdu );
236
237 acpdu.Write( *inConnection.GetProtocol() );
238 inConnection.GetProtocol()->flush();
239
240 return eSta3WaitLocalAssoc;
241 } else {
242
243 outWaitingForEvent = false;
244 outRaisedEvent = eAASSOCIATEresponseReject;
245 AAssociateRJPDU thePDU;
246 thePDU.Write(*inConnection.GetProtocol());
247 inConnection.GetProtocol()->flush();
248 inConnection.GetTimer().Stop();
249 return eSta13AwaitingClose;
250 }
251
252 }
253
254 //Send A-ASSOCIATE-AC PDU
PerformAction(Subject *,ULEvent &,ULConnection &,bool & outWaitingForEvent,EEventID & outRaisedEvent)255 EStateID ULActionAE7::PerformAction(Subject *, ULEvent& , ULConnection& ,
256 bool& outWaitingForEvent, EEventID& outRaisedEvent)
257 {
258 outWaitingForEvent = true;
259 outRaisedEvent = eEventDoesNotExist;
260 return eSta6TransferReady;
261 }
262
263 //Send A-ASSOCIATE-RJ PDU and start ARTIM timer
PerformAction(Subject *,ULEvent &,ULConnection & inConnection,bool & outWaitingForEvent,EEventID & outRaisedEvent)264 EStateID ULActionAE8::PerformAction(Subject *, ULEvent& , ULConnection& inConnection,
265 bool& outWaitingForEvent, EEventID& outRaisedEvent)
266 {
267 AAssociateRJPDU thePDU;
268 thePDU.Write(*inConnection.GetProtocol());
269 inConnection.GetTimer().Start();
270 outWaitingForEvent = false;
271 outRaisedEvent = eAASSOCIATEresponseReject;
272
273 return eSta13AwaitingClose;
274 }
275
276 } // end namespace network
277 } // end namespace gdcm
278