Mercurial > hg > orthanc
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 { |