Mercurial > hg > orthanc
comparison OrthancFramework/Sources/DicomNetworking/Internals/GetScp.cpp @ 4258:6f5d4bfb2c90
C-GET SCP: Fix responses and handling of cancel
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 26 Oct 2020 12:23:36 +0100 |
parents | 7112a8af0b63 |
children | 756126cd2219 |
comparison
equal
deleted
inserted
replaced
4257:c046d559edb3 | 4258:6f5d4bfb2c90 |
---|---|
97 | 97 |
98 std::string remoteIp_; | 98 std::string remoteIp_; |
99 std::string remoteAet_; | 99 std::string remoteAet_; |
100 std::string calledAet_; | 100 std::string calledAet_; |
101 int timeout_; | 101 int timeout_; |
102 bool canceled_; | |
102 | 103 |
103 GetScpData() : | 104 GetScpData() : |
104 handler_(NULL), | 105 handler_(NULL), |
105 lastRequest_(NULL), | 106 lastRequest_(NULL), |
106 assoc_(NULL), | 107 assoc_(NULL), |
107 timeout_(0) | 108 timeout_(0), |
109 canceled_(false) | |
108 { | 110 { |
109 }; | 111 }; |
110 }; | 112 }; |
111 | 113 |
112 static DcmDataset *BuildFailedInstanceList(const std::string& failedUIDs) | 114 static DcmDataset *BuildFailedInstanceList(const std::string& failedUIDs) |
126 } | 128 } |
127 | 129 |
128 return rspIds.release(); | 130 return rspIds.release(); |
129 } | 131 } |
130 } | 132 } |
133 | |
134 | |
135 static void FillResponse(T_DIMSE_C_GetRSP& response, | |
136 DcmDataset** failedIdentifiers, | |
137 const IGetRequestHandler& handler) | |
138 { | |
139 response.DimseStatus = STATUS_Success; | |
140 | |
141 size_t processedCount = (handler.GetCompletedCount() + | |
142 handler.GetFailedCount() + | |
143 handler.GetWarningCount()); | |
144 | |
145 if (processedCount > handler.GetSubOperationCount()) | |
146 { | |
147 throw OrthancException(ErrorCode_InternalError); | |
148 } | |
149 | |
150 response.NumberOfRemainingSubOperations = (handler.GetSubOperationCount() - processedCount); | |
151 response.NumberOfCompletedSubOperations = handler.GetCompletedCount(); | |
152 response.NumberOfFailedSubOperations = handler.GetFailedCount(); | |
153 response.NumberOfWarningSubOperations = handler.GetWarningCount(); | |
154 | |
155 // http://dicom.nema.org/medical/dicom/current/output/chtml/part04/sect_C.4.3.3.html | |
156 | |
157 if (handler.GetFailedCount() > 0 || | |
158 handler.GetWarningCount() > 0) | |
159 { | |
160 /** | |
161 * "Warning if one or more sub-operations were successfully | |
162 * completed and one or more sub-operations were unsuccessful | |
163 * or had a status of warning. Warning if all sub-operations | |
164 * had a status of Warning" | |
165 **/ | |
166 response.DimseStatus = STATUS_GET_Warning_SubOperationsCompleteOneOrMoreFailures; | |
167 } | |
168 | |
169 if (handler.GetFailedCount() > 0 && | |
170 handler.GetFailedCount() == handler.GetSubOperationCount()) | |
171 { | |
172 /** | |
173 * "Failure or Refused if all sub-operations were | |
174 * unsuccessful." => We choose to generate a "Refused - Out | |
175 * of Resources - Unable to perform suboperations" status. | |
176 */ | |
177 response.DimseStatus = STATUS_GET_Refused_OutOfResourcesSubOperations; | |
178 } | |
179 | |
180 *failedIdentifiers = BuildFailedInstanceList(handler.GetFailedUids()); | |
181 } | |
182 | |
131 | 183 |
132 static void GetScpCallback( | 184 static void GetScpCallback( |
133 /* in */ | 185 /* in */ |
134 void *callbackData, | 186 void *callbackData, |
135 OFBool cancelled, | 187 OFBool cancelled, |
139 /* out */ | 191 /* out */ |
140 T_DIMSE_C_GetRSP *response, | 192 T_DIMSE_C_GetRSP *response, |
141 DcmDataset **responseIdentifiers, | 193 DcmDataset **responseIdentifiers, |
142 DcmDataset **statusDetail) | 194 DcmDataset **statusDetail) |
143 { | 195 { |
196 assert(response != NULL); | |
197 assert(responseIdentifiers != NULL); | |
198 | |
144 bzero(response, sizeof(T_DIMSE_C_GetRSP)); | 199 bzero(response, sizeof(T_DIMSE_C_GetRSP)); |
145 *statusDetail = NULL; | 200 *statusDetail = NULL; |
146 *responseIdentifiers = NULL; | 201 *responseIdentifiers = NULL; |
147 | 202 |
148 GetScpData& data = *reinterpret_cast<GetScpData*>(callbackData); | 203 GetScpData& data = *reinterpret_cast<GetScpData*>(callbackData); |
178 LOG(ERROR) << "IGetRequestHandler Failed: Internal error lastRequestIdentifier"; | 233 LOG(ERROR) << "IGetRequestHandler Failed: Internal error lastRequestIdentifier"; |
179 response->DimseStatus = STATUS_GET_Failed_UnableToProcess; | 234 response->DimseStatus = STATUS_GET_Failed_UnableToProcess; |
180 return; | 235 return; |
181 } | 236 } |
182 | 237 |
183 if (data.handler_->GetRemainingCount() == 0) | 238 if (data.canceled_) |
184 { | 239 { |
185 response->DimseStatus = STATUS_Success; | 240 LOG(ERROR) << "IGetRequestHandler Failed: Cannot pursue a request that was canceled by the SCU"; |
241 response->DimseStatus = STATUS_GET_Failed_UnableToProcess; | |
242 return; | |
243 } | |
244 | |
245 if (data.handler_->GetSubOperationCount() == | |
246 data.handler_->GetCompletedCount() + | |
247 data.handler_->GetFailedCount() + | |
248 data.handler_->GetWarningCount()) | |
249 { | |
250 // We're all done | |
251 FillResponse(*response, responseIdentifiers, *data.handler_); | |
186 } | 252 } |
187 else | 253 else |
188 { | 254 { |
189 IGetRequestHandler::Status status; | 255 bool isContinue; |
190 | 256 |
191 try | 257 try |
192 { | 258 { |
193 status = data.handler_->DoNext(data.assoc_); | 259 isContinue = data.handler_->DoNext(data.assoc_); |
194 } | 260 } |
195 catch (OrthancException& e) | 261 catch (OrthancException& e) |
196 { | 262 { |
197 // Internal error! | 263 // Internal error! |
198 LOG(ERROR) << "IGetRequestHandler Failed: " << e.What(); | 264 LOG(ERROR) << "IGetRequestHandler Failed: " << e.What(); |
265 FillResponse(*response, responseIdentifiers, *data.handler_); | |
266 | |
267 // Fix the status code that is computed by "FillResponse()" | |
199 response->DimseStatus = STATUS_GET_Failed_UnableToProcess; | 268 response->DimseStatus = STATUS_GET_Failed_UnableToProcess; |
200 return; | 269 return; |
201 } | 270 } |
202 | 271 |
203 if (status == STATUS_Success) | 272 FillResponse(*response, responseIdentifiers, *data.handler_); |
204 { | 273 |
205 if (responseCount < static_cast<int>(data.handler_->GetRemainingCount())) | 274 if (isContinue) |
206 { | 275 { |
207 response->DimseStatus = STATUS_Pending; | 276 response->DimseStatus = STATUS_Pending; |
208 } | |
209 else | |
210 { | |
211 response->DimseStatus = STATUS_Success; | |
212 } | |
213 } | 277 } |
214 else | 278 else |
215 { | 279 { |
216 response->DimseStatus = STATUS_GET_Failed_UnableToProcess; | 280 response->DimseStatus = STATUS_GET_Cancel_SubOperationsTerminatedDueToCancelIndication; |
217 | 281 data.canceled_ = true; |
218 if (data.handler_->GetFailedCount() > 0 || | 282 } |
219 data.handler_->GetWarningCount() > 0) | 283 } |
220 { | |
221 response->DimseStatus = STATUS_GET_Warning_SubOperationsCompleteOneOrMoreFailures; | |
222 } | |
223 | |
224 /* | |
225 * if all the sub-operations failed then we need to generate | |
226 * a failed or refused status. cf. DICOM part 4, C.4.3.3.1 | |
227 * we choose to generate a "Refused - Out of Resources - | |
228 * Unable to perform suboperations" status. | |
229 */ | |
230 if ((data.handler_->GetFailedCount() > 0) && | |
231 ((data.handler_->GetCompletedCount() + | |
232 data.handler_->GetWarningCount()) == 0)) | |
233 { | |
234 response->DimseStatus = STATUS_GET_Refused_OutOfResourcesSubOperations; | |
235 } | |
236 | |
237 *responseIdentifiers = BuildFailedInstanceList(data.handler_->GetFailedUids()); | |
238 } | |
239 } | |
240 | |
241 response->NumberOfRemainingSubOperations = data.handler_->GetRemainingCount(); | |
242 response->NumberOfCompletedSubOperations = data.handler_->GetCompletedCount(); | |
243 response->NumberOfFailedSubOperations = data.handler_->GetFailedCount(); | |
244 response->NumberOfWarningSubOperations = data.handler_->GetWarningCount(); | |
245 } | 284 } |
246 } | 285 } |
247 | 286 |
248 OFCondition Internals::getScp(T_ASC_Association * assoc, | 287 OFCondition Internals::getScp(T_ASC_Association * assoc, |
249 T_DIMSE_Message * msg, | 288 T_DIMSE_Message * msg, |