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,