comparison Core/DicomNetworking/DicomUserConnection.cpp @ 3208:c4e1977e5ed7

improved logging in DicomUserConnection
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 08 Feb 2019 08:38:45 +0100
parents c8b75e207a82
children 4924972bce77
comparison
equal deleted inserted replaced
3207:4246ce5c2aa5 3208:c4e1977e5ed7
162 const std::string& moveOriginatorAET, 162 const std::string& moveOriginatorAET,
163 uint16_t moveOriginatorID); 163 uint16_t moveOriginatorID);
164 }; 164 };
165 165
166 166
167 static void Check(const OFCondition& cond) 167 static void Check(const OFCondition& cond,
168 const std::string& aet)
168 { 169 {
169 if (cond.bad()) 170 if (cond.bad())
170 { 171 {
172 // Reformat the error message from DCMTK by turning multiline
173 // errors into a single line
174
175 std::string s(cond.text());
176 std::string info;
177 info.reserve(s.size());
178
179 bool isMultiline = false;
180 for (size_t i = 0; i < s.size(); i++)
181 {
182 if (s[i] == '\r')
183 {
184 // Ignore
185 }
186 else if (s[i] == '\n')
187 {
188 if (isMultiline)
189 {
190 info += "; ";
191 }
192 else
193 {
194 info += " (";
195 isMultiline = true;
196 }
197 }
198 else
199 {
200 info.push_back(s[i]);
201 }
202 }
203
204 if (isMultiline)
205 {
206 info += ")";
207 }
208
171 throw OrthancException(ErrorCode_NetworkProtocol, 209 throw OrthancException(ErrorCode_NetworkProtocol,
172 "DicomUserConnection: " + std::string(cond.text())); 210 "DicomUserConnection to AET \"" + aet + "\": " + info);
173 } 211 }
174 } 212 }
175 213
176 void DicomUserConnection::PImpl::CheckIsOpen() const 214 void DicomUserConnection::PImpl::CheckIsOpen() const
177 { 215 {
191 229
192 static void RegisterStorageSOPClass(T_ASC_Parameters* params, 230 static void RegisterStorageSOPClass(T_ASC_Parameters* params,
193 unsigned int& presentationContextId, 231 unsigned int& presentationContextId,
194 const std::string& sopClass, 232 const std::string& sopClass,
195 const char* asPreferred[], 233 const char* asPreferred[],
196 std::vector<const char*>& asFallback) 234 std::vector<const char*>& asFallback,
235 const std::string& aet)
197 { 236 {
198 Check(ASC_addPresentationContext(params, presentationContextId, 237 Check(ASC_addPresentationContext(params, presentationContextId,
199 sopClass.c_str(), asPreferred, 1)); 238 sopClass.c_str(), asPreferred, 1), aet);
200 presentationContextId += 2; 239 presentationContextId += 2;
201 240
202 if (asFallback.size() > 0) 241 if (asFallback.size() > 0)
203 { 242 {
204 Check(ASC_addPresentationContext(params, presentationContextId, 243 Check(ASC_addPresentationContext(params, presentationContextId,
205 sopClass.c_str(), &asFallback[0], asFallback.size())); 244 sopClass.c_str(), &asFallback[0], asFallback.size()), aet);
206 presentationContextId += 2; 245 presentationContextId += 2;
207 } 246 }
208 } 247 }
209 248
210 249
234 273
235 for (std::list<std::string>::const_iterator it = reservedStorageSOPClasses_.begin(); 274 for (std::list<std::string>::const_iterator it = reservedStorageSOPClasses_.begin();
236 it != reservedStorageSOPClasses_.end(); ++it) 275 it != reservedStorageSOPClasses_.end(); ++it)
237 { 276 {
238 RegisterStorageSOPClass(pimpl_->params_, presentationContextId, 277 RegisterStorageSOPClass(pimpl_->params_, presentationContextId,
239 *it, asPreferred, asFallback); 278 *it, asPreferred, asFallback, remoteAet_);
240 } 279 }
241 280
242 for (std::set<std::string>::const_iterator it = storageSOPClasses_.begin(); 281 for (std::set<std::string>::const_iterator it = storageSOPClasses_.begin();
243 it != storageSOPClasses_.end(); ++it) 282 it != storageSOPClasses_.end(); ++it)
244 { 283 {
245 RegisterStorageSOPClass(pimpl_->params_, presentationContextId, 284 RegisterStorageSOPClass(pimpl_->params_, presentationContextId,
246 *it, asPreferred, asFallback); 285 *it, asPreferred, asFallback, remoteAet_);
247 } 286 }
248 287
249 for (std::set<std::string>::const_iterator it = defaultStorageSOPClasses_.begin(); 288 for (std::set<std::string>::const_iterator it = defaultStorageSOPClasses_.begin();
250 it != defaultStorageSOPClasses_.end(); ++it) 289 it != defaultStorageSOPClasses_.end(); ++it)
251 { 290 {
252 RegisterStorageSOPClass(pimpl_->params_, presentationContextId, 291 RegisterStorageSOPClass(pimpl_->params_, presentationContextId,
253 *it, asPreferred, asFallback); 292 *it, asPreferred, asFallback, remoteAet_);
254 } 293 }
255 } 294 }
256 295
257 296
258 static bool IsGenericTransferSyntax(const std::string& syntax) 297 static bool IsGenericTransferSyntax(const std::string& syntax)
267 DicomUserConnection& connection, 306 DicomUserConnection& connection,
268 const std::string& moveOriginatorAET, 307 const std::string& moveOriginatorAET,
269 uint16_t moveOriginatorID) 308 uint16_t moveOriginatorID)
270 { 309 {
271 DcmFileFormat dcmff; 310 DcmFileFormat dcmff;
272 Check(dcmff.read(is, EXS_Unknown, EGL_noChange, DCM_MaxReadLength)); 311 Check(dcmff.read(is, EXS_Unknown, EGL_noChange, DCM_MaxReadLength), connection.remoteAet_);
273 312
274 // Determine the storage SOP class UID for this instance 313 // Determine the storage SOP class UID for this instance
275 static const DcmTagKey DCM_SOP_CLASS_UID(0x0008, 0x0016); 314 static const DcmTagKey DCM_SOP_CLASS_UID(0x0008, 0x0016);
276 OFString sopClassUid; 315 OFString sopClassUid;
277 if (dcmff.getDataset()->findAndGetOFString(DCM_SOP_CLASS_UID, sopClassUid).good()) 316 if (dcmff.getDataset()->findAndGetOFString(DCM_SOP_CLASS_UID, sopClassUid).good())
377 T_DIMSE_C_StoreRSP rsp; 416 T_DIMSE_C_StoreRSP rsp;
378 DcmDataset* statusDetail = NULL; 417 DcmDataset* statusDetail = NULL;
379 Check(DIMSE_storeUser(assoc_, presID, &request, 418 Check(DIMSE_storeUser(assoc_, presID, &request,
380 NULL, dcmff.getDataset(), /*progressCallback*/ NULL, NULL, 419 NULL, dcmff.getDataset(), /*progressCallback*/ NULL, NULL,
381 /*opt_blockMode*/ DIMSE_BLOCKING, /*opt_dimse_timeout*/ dimseTimeout_, 420 /*opt_blockMode*/ DIMSE_BLOCKING, /*opt_dimse_timeout*/ dimseTimeout_,
382 &rsp, &statusDetail, NULL)); 421 &rsp, &statusDetail, NULL), connection.remoteAet_);
383 422
384 if (statusDetail != NULL) 423 if (statusDetail != NULL)
385 { 424 {
386 delete statusDetail; 425 delete statusDetail;
387 } 426 }
554 T_ASC_Association* association, 593 T_ASC_Association* association,
555 DcmDataset* dataset, 594 DcmDataset* dataset,
556 const char* sopClass, 595 const char* sopClass,
557 bool isWorklist, 596 bool isWorklist,
558 const char* level, 597 const char* level,
559 uint32_t dimseTimeout) 598 uint32_t dimseTimeout,
599 const std::string& remoteAet)
560 { 600 {
561 assert(isWorklist ^ (level != NULL)); 601 assert(isWorklist ^ (level != NULL));
562 602
563 FindPayload payload; 603 FindPayload payload;
564 payload.answers = &answers; 604 payload.answers = &answers;
598 if (statusDetail) 638 if (statusDetail)
599 { 639 {
600 delete statusDetail; 640 delete statusDetail;
601 } 641 }
602 642
603 Check(cond); 643 Check(cond, remoteAet);
604 } 644 }
605 645
606 646
607 void DicomUserConnection::Find(DicomFindAnswers& result, 647 void DicomUserConnection::Find(DicomFindAnswers& result,
608 ResourceType level, 648 ResourceType level,
718 default: 758 default:
719 throw OrthancException(ErrorCode_ParameterOutOfRange); 759 throw OrthancException(ErrorCode_ParameterOutOfRange);
720 } 760 }
721 761
722 assert(clevel != NULL && sopClass != NULL); 762 assert(clevel != NULL && sopClass != NULL);
723 ExecuteFind(result, pimpl_->assoc_, dataset, sopClass, false, clevel, pimpl_->dimseTimeout_); 763 ExecuteFind(result, pimpl_->assoc_, dataset, sopClass, false, clevel,
764 pimpl_->dimseTimeout_, remoteAet_);
724 } 765 }
725 766
726 767
727 void DicomUserConnection::MoveInternal(const std::string& targetAet, 768 void DicomUserConnection::MoveInternal(const std::string& targetAet,
728 ResourceType level, 769 ResourceType level,
801 if (responseIdentifiers) 842 if (responseIdentifiers)
802 { 843 {
803 delete responseIdentifiers; 844 delete responseIdentifiers;
804 } 845 }
805 846
806 Check(cond); 847 Check(cond, remoteAet_);
807 } 848 }
808 849
809 850
810 void DicomUserConnection::ResetStorageSOPClasses() 851 void DicomUserConnection::ResetStorageSOPClasses()
811 { 852 {
970 LOG(INFO) << "Opening a DICOM SCU connection from AET \"" << GetLocalApplicationEntityTitle() 1011 LOG(INFO) << "Opening a DICOM SCU connection from AET \"" << GetLocalApplicationEntityTitle()
971 << "\" to AET \"" << GetRemoteApplicationEntityTitle() << "\" on host " 1012 << "\" to AET \"" << GetRemoteApplicationEntityTitle() << "\" on host "
972 << GetRemoteHost() << ":" << GetRemotePort() 1013 << GetRemoteHost() << ":" << GetRemotePort()
973 << " (manufacturer: " << EnumerationToString(GetRemoteManufacturer()) << ")"; 1014 << " (manufacturer: " << EnumerationToString(GetRemoteManufacturer()) << ")";
974 1015
975 Check(ASC_initializeNetwork(NET_REQUESTOR, 0, /*opt_acse_timeout*/ pimpl_->acseTimeout_, &pimpl_->net_)); 1016 Check(ASC_initializeNetwork(NET_REQUESTOR, 0, /*opt_acse_timeout*/ pimpl_->acseTimeout_, &pimpl_->net_), remoteAet_);
976 Check(ASC_createAssociationParameters(&pimpl_->params_, /*opt_maxReceivePDULength*/ ASC_DEFAULTMAXPDU)); 1017 Check(ASC_createAssociationParameters(&pimpl_->params_, /*opt_maxReceivePDULength*/ ASC_DEFAULTMAXPDU), remoteAet_);
977 1018
978 // Set this application's title and the called application's title in the params 1019 // Set this application's title and the called application's title in the params
979 Check(ASC_setAPTitles(pimpl_->params_, localAet_.c_str(), remoteAet_.c_str(), NULL)); 1020 Check(ASC_setAPTitles(pimpl_->params_, localAet_.c_str(), remoteAet_.c_str(), NULL), remoteAet_);
980 1021
981 // Set the network addresses of the local and remote entities 1022 // Set the network addresses of the local and remote entities
982 char localHost[HOST_NAME_MAX]; 1023 char localHost[HOST_NAME_MAX];
983 gethostname(localHost, HOST_NAME_MAX - 1); 1024 gethostname(localHost, HOST_NAME_MAX - 1);
984 1025
989 #else 1030 #else
990 snprintf 1031 snprintf
991 #endif 1032 #endif
992 (remoteHostAndPort, HOST_NAME_MAX - 1, "%s:%d", remoteHost_.c_str(), remotePort_); 1033 (remoteHostAndPort, HOST_NAME_MAX - 1, "%s:%d", remoteHost_.c_str(), remotePort_);
993 1034
994 Check(ASC_setPresentationAddresses(pimpl_->params_, localHost, remoteHostAndPort)); 1035 Check(ASC_setPresentationAddresses(pimpl_->params_, localHost, remoteHostAndPort), remoteAet_);
995 1036
996 // Set various options 1037 // Set various options
997 Check(ASC_setTransportLayerType(pimpl_->params_, /*opt_secureConnection*/ false)); 1038 Check(ASC_setTransportLayerType(pimpl_->params_, /*opt_secureConnection*/ false), remoteAet_);
998 1039
999 SetupPresentationContexts(preferredTransferSyntax_); 1040 SetupPresentationContexts(preferredTransferSyntax_);
1000 1041
1001 // Do the association 1042 // Do the association
1002 Check(ASC_requestAssociation(pimpl_->net_, pimpl_->params_, &pimpl_->assoc_)); 1043 Check(ASC_requestAssociation(pimpl_->net_, pimpl_->params_, &pimpl_->assoc_), remoteAet_);
1003 1044
1004 if (ASC_countAcceptedPresentationContexts(pimpl_->params_) == 0) 1045 if (ASC_countAcceptedPresentationContexts(pimpl_->params_) == 0)
1005 { 1046 {
1006 throw OrthancException(ErrorCode_NoPresentationContext); 1047 throw OrthancException(ErrorCode_NoPresentationContext);
1007 } 1048 }
1075 CheckIsOpen(); 1116 CheckIsOpen();
1076 DIC_US status; 1117 DIC_US status;
1077 Check(DIMSE_echoUser(pimpl_->assoc_, pimpl_->assoc_->nextMsgID++, 1118 Check(DIMSE_echoUser(pimpl_->assoc_, pimpl_->assoc_->nextMsgID++,
1078 /*opt_blockMode*/ DIMSE_BLOCKING, 1119 /*opt_blockMode*/ DIMSE_BLOCKING,
1079 /*opt_dimse_timeout*/ pimpl_->dimseTimeout_, 1120 /*opt_dimse_timeout*/ pimpl_->dimseTimeout_,
1080 &status, NULL)); 1121 &status, NULL), remoteAet_);
1081 return status == STATUS_Success; 1122 return status == STATUS_Success;
1082 } 1123 }
1083 1124
1084 1125
1085 static void TestAndCopyTag(DicomMap& result, 1126 static void TestAndCopyTag(DicomMap& result,
1274 CheckIsOpen(); 1315 CheckIsOpen();
1275 1316
1276 DcmDataset* dataset = query.GetDcmtkObject().getDataset(); 1317 DcmDataset* dataset = query.GetDcmtkObject().getDataset();
1277 const char* sopClass = UID_FINDModalityWorklistInformationModel; 1318 const char* sopClass = UID_FINDModalityWorklistInformationModel;
1278 1319
1279 ExecuteFind(result, pimpl_->assoc_, dataset, sopClass, true, NULL, pimpl_->dimseTimeout_); 1320 ExecuteFind(result, pimpl_->assoc_, dataset, sopClass, true,
1321 NULL, pimpl_->dimseTimeout_, remoteAet_);
1280 } 1322 }
1281 1323
1282 1324
1283 void DicomUserConnection::SetDefaultTimeout(uint32_t seconds) 1325 void DicomUserConnection::SetDefaultTimeout(uint32_t seconds)
1284 { 1326 {