comparison OrthancServer/Sources/main.cpp @ 4899:3ab57510f6dd proto-filter-instance-returning-error-code

integration mainline->proto-filter-instance-returning-error-code
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sun, 20 Feb 2022 12:59:30 +0100
parents 656784ac6759 6eff25f70121
children
comparison
equal deleted inserted replaced
4791:656784ac6759 4899:3ab57510f6dd
1 /** 1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store 2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics 3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium 4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2021 Osimis S.A., Belgium 5 * Copyright (C) 2017-2022 Osimis S.A., Belgium
6 * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium
6 * 7 *
7 * This program is free software: you can redistribute it and/or 8 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as 9 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, either version 3 of the 10 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version. 11 * License, or (at your option) any later version.
11 *
12 * In addition, as a special exception, the copyright holders of this
13 * program give permission to link the code of its release with the
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it
15 * that use the same license as the "OpenSSL" library), and distribute
16 * the linked executables. You must obey the GNU General Public License
17 * in all respects for all of the code used other than "OpenSSL". If you
18 * modify file(s) with this exception, you may extend this exception to
19 * your version of the file(s), but you are not obligated to do so. If
20 * you do not wish to do so, delete this exception statement from your
21 * version. If you delete this exception statement from all source files
22 * in the program, then also delete it here.
23 * 12 *
24 * This program is distributed in the hope that it will be useful, but 13 * This program is distributed in the hope that it will be useful, but
25 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * General Public License for more details. 16 * General Public License for more details.
82 context_(context) 71 context_(context)
83 { 72 {
84 } 73 }
85 74
86 75
87 virtual int Handle(DcmDataset& dicom, 76 virtual uint16_t Handle(DcmDataset& dicom,
88 const std::string& remoteIp, 77 const std::string& remoteIp,
89 const std::string& remoteAet, 78 const std::string& remoteAet,
90 const std::string& calledAet) ORTHANC_OVERRIDE 79 const std::string& calledAet) ORTHANC_OVERRIDE
91 { 80 {
92 std::unique_ptr<DicomInstanceToStore> toStore(DicomInstanceToStore::CreateFromDcmDataset(dicom)); 81 std::unique_ptr<DicomInstanceToStore> toStore(DicomInstanceToStore::CreateFromDcmDataset(dicom));
93 82
94 if (toStore->GetBufferSize() > 0) 83 if (toStore->GetBufferSize() > 0)
95 { 84 {
96 toStore->SetOrigin(DicomInstanceOrigin::FromDicomProtocol 85 toStore->SetOrigin(DicomInstanceOrigin::FromDicomProtocol
97 (remoteIp.c_str(), remoteAet.c_str(), calledAet.c_str())); 86 (remoteIp.c_str(), remoteAet.c_str(), calledAet.c_str()));
98 87
99 std::string id; 88 std::string id;
100 StoreStatus res = context_.Store(id, *toStore, StoreInstanceMode_Default); 89 ServerContext::StoreResult result = context_.Store(id, *toStore, StoreInstanceMode_Default);
101 if (res == StoreStatus_FilteredOut) 90
102 { 91 if (result.GetStatus() == StoreStatus_FilteredOut)
103 return 0xA700; // C-Store "Out of Resources" error code 92 {
104 } 93 return STATUS_STORE_Refused_OutOfResources; // C-Store "Out of Resources" error code (0xa700)
105 return 0x0000; 94 }
106 } 95 else
107 96 {
108 return 0xC000; // C-Store "Cannot understand" error code 97 return result.GetCStoreStatusCode();
98 }
99 }
100
101 return STATUS_STORE_Error_CannotUnderstand; // C-Store "Cannot understand" error code (0xc000)
109 } 102 }
110 }; 103 };
111 104
112 105
113 106
283 { 276 {
284 private: 277 private:
285 ServerContext& context_; 278 ServerContext& context_;
286 bool alwaysAllowEcho_; 279 bool alwaysAllowEcho_;
287 bool alwaysAllowFind_; // New in Orthanc 1.9.0 280 bool alwaysAllowFind_; // New in Orthanc 1.9.0
281 bool alwaysAllowFindWorklist_; // New in Orthanc 1.10.0
288 bool alwaysAllowGet_; // New in Orthanc 1.9.0 282 bool alwaysAllowGet_; // New in Orthanc 1.9.0
289 bool alwaysAllowMove_; // New in Orthanc 1.9.7 283 bool alwaysAllowMove_; // New in Orthanc 1.9.7
290 bool alwaysAllowStore_; 284 bool alwaysAllowStore_;
291 285
292 public: 286 public:
295 { 289 {
296 { 290 {
297 OrthancConfiguration::ReaderLock lock; 291 OrthancConfiguration::ReaderLock lock;
298 alwaysAllowEcho_ = lock.GetConfiguration().GetBooleanParameter("DicomAlwaysAllowEcho", true); 292 alwaysAllowEcho_ = lock.GetConfiguration().GetBooleanParameter("DicomAlwaysAllowEcho", true);
299 alwaysAllowFind_ = lock.GetConfiguration().GetBooleanParameter("DicomAlwaysAllowFind", false); 293 alwaysAllowFind_ = lock.GetConfiguration().GetBooleanParameter("DicomAlwaysAllowFind", false);
294 alwaysAllowFindWorklist_ = lock.GetConfiguration().GetBooleanParameter("DicomAlwaysAllowFindWorklist", false);
300 alwaysAllowGet_ = lock.GetConfiguration().GetBooleanParameter("DicomAlwaysAllowGet", false); 295 alwaysAllowGet_ = lock.GetConfiguration().GetBooleanParameter("DicomAlwaysAllowGet", false);
301 alwaysAllowMove_ = lock.GetConfiguration().GetBooleanParameter("DicomAlwaysAllowMove", false); 296 alwaysAllowMove_ = lock.GetConfiguration().GetBooleanParameter("DicomAlwaysAllowMove", false);
302 alwaysAllowStore_ = lock.GetConfiguration().GetBooleanParameter("DicomAlwaysAllowStore", true); 297 alwaysAllowStore_ = lock.GetConfiguration().GetBooleanParameter("DicomAlwaysAllowStore", true);
303 } 298 }
304 299
305 if (alwaysAllowFind_) 300 if (alwaysAllowFind_)
306 { 301 {
307 LOG(WARNING) << "Security risk in DICOM SCP: C-FIND requests are always allowed, even from unknown modalities"; 302 LOG(WARNING) << "Security risk in DICOM SCP: C-FIND requests are always allowed, even from unknown modalities";
308 } 303 }
309 304
305 if (alwaysAllowFindWorklist_)
306 {
307 LOG(WARNING) << "Security risk in DICOM SCP: C-FIND requests for worklists are always allowed, even from unknown modalities";
308 }
309
310 if (alwaysAllowGet_) 310 if (alwaysAllowGet_)
311 { 311 {
312 LOG(WARNING) << "Security risk in DICOM SCP: C-GET requests are always allowed, even from unknown modalities"; 312 LOG(WARNING) << "Security risk in DICOM SCP: C-GET requests are always allowed, even from unknown modalities";
313 } 313 }
314 314
325 LOG(INFO) << "Incoming connection from AET " << remoteAet 325 LOG(INFO) << "Incoming connection from AET " << remoteAet
326 << " on IP " << remoteIp << ", calling AET " << calledAet; 326 << " on IP " << remoteIp << ", calling AET " << calledAet;
327 327
328 if (alwaysAllowEcho_ || 328 if (alwaysAllowEcho_ ||
329 alwaysAllowFind_ || 329 alwaysAllowFind_ ||
330 alwaysAllowFindWorklist_ ||
330 alwaysAllowGet_ || 331 alwaysAllowGet_ ||
331 alwaysAllowMove_ || 332 alwaysAllowMove_ ||
332 alwaysAllowStore_) 333 alwaysAllowStore_)
333 { 334 {
334 return true; 335 return true;
342 343
343 static void ReportDisallowedCommand(const std::string& remoteIp, 344 static void ReportDisallowedCommand(const std::string& remoteIp,
344 const std::string& remoteAet, 345 const std::string& remoteAet,
345 DicomRequestType type) 346 DicomRequestType type)
346 { 347 {
347 LOG(WARNING) << "Unable to check DICOM authorization for AET " << remoteAet 348 LOG(WARNING) << "DICOM authorization rejected for AET " << remoteAet
348 << " on IP " << remoteIp << ": The DICOM command " 349 << " on IP " << remoteIp << ": The DICOM command "
349 << EnumerationToString(type) << " is not allowed for this modality " 350 << EnumerationToString(type) << " is not allowed for this modality "
350 << "according to configuration option \"DicomModalities\""; 351 << "according to configuration option \"DicomModalities\"";
351 } 352 }
352 353
369 alwaysAllowFind_) 370 alwaysAllowFind_)
370 { 371 {
371 // Incoming C-Find requests are always accepted, even from unknown AET 372 // Incoming C-Find requests are always accepted, even from unknown AET
372 return true; 373 return true;
373 } 374 }
375 else if (type == DicomRequestType_FindWorklist &&
376 alwaysAllowFindWorklist_)
377 {
378 // Incoming C-Find requests for worklists are always accepted, even from unknown AET
379 return true;
380 }
374 else if (type == DicomRequestType_Store && 381 else if (type == DicomRequestType_Store &&
375 alwaysAllowStore_) 382 alwaysAllowStore_)
376 { 383 {
377 // Incoming C-Store requests are always accepted, even from unknown AET 384 // Incoming C-Store requests are always accepted, even from unknown AET
378 return true; 385 return true;
400 checkIp = lock.GetConfiguration().GetBooleanParameter("DicomCheckModalityHost", false); 407 checkIp = lock.GetConfiguration().GetBooleanParameter("DicomCheckModalityHost", false);
401 } 408 }
402 409
403 if (modalities.empty()) 410 if (modalities.empty())
404 { 411 {
405 LOG(WARNING) << "Unable to check DICOM authorization for AET " << remoteAet 412 LOG(WARNING) << "DICOM authorization rejected for AET " << remoteAet
406 << " on IP " << remoteIp << ": This AET is not listed in " 413 << " on IP " << remoteIp << ": This AET is not listed in "
407 << "configuration option \"DicomModalities\""; 414 << "configuration option \"DicomModalities\"";
408 return false; 415 return false;
409 } 416 }
410 else if (modalities.size() == 1) 417 else if (modalities.size() == 1)
411 { 418 {
412 // DicomCheckModalityHost is true: check if the IP match the configured IP 419 // DicomCheckModalityHost is true: check if the IP match the configured IP
413 if (checkIp && 420 if (checkIp &&
414 remoteIp != modalities.front().GetHost()) 421 remoteIp != modalities.front().GetHost())
415 { 422 {
416 LOG(WARNING) << "Unable to check DICOM authorization for AET " << remoteAet 423 LOG(WARNING) << "DICOM authorization rejected for AET " << remoteAet
417 << " on IP " << remoteIp << ": Its IP address should be " 424 << " on IP " << remoteIp << ": Its IP address should be "
418 << modalities.front().GetHost() 425 << modalities.front().GetHost()
419 << " according to configuration option \"DicomModalities\""; 426 << " according to configuration option \"DicomModalities\"";
420 return false; 427 return false;
421 } 428 }
447 return false; 454 return false;
448 } 455 }
449 } 456 }
450 } 457 }
451 458
452 LOG(WARNING) << "Unable to check DICOM authorization for AET " << remoteAet 459 LOG(WARNING) << "DICOM authorization rejected for AET " << remoteAet
453 << " on IP " << remoteIp << ": " << modalities.size() 460 << " on IP " << remoteIp << ": " << modalities.size()
454 << " modalites found with this AET in configuration option " 461 << " modalites found with this AET in configuration option "
455 << "\"DicomModalities\", but none of them matches the IP"; 462 << "\"DicomModalities\", but none of them matches the IP";
456 return false; 463 return false;
457 } 464 }
716 static void PrintVersion(const char* path) 723 static void PrintVersion(const char* path)
717 { 724 {
718 std::cout 725 std::cout
719 << path << " " << ORTHANC_VERSION << std::endl 726 << path << " " << ORTHANC_VERSION << std::endl
720 << "Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics Department, University Hospital of Liege (Belgium)" << std::endl 727 << "Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics Department, University Hospital of Liege (Belgium)" << std::endl
721 << "Copyright (C) 2017-2021 Osimis S.A. (Belgium)" << std::endl 728 << "Copyright (C) 2017-2022 Osimis S.A. (Belgium)" << std::endl
722 << "Licensing GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>, with OpenSSL exception." << std::endl 729 << "Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain (Belgium)" << std::endl
730 << "Licensing GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>." << std::endl
723 << "This is free software: you are free to change and redistribute it." << std::endl 731 << "This is free software: you are free to change and redistribute it." << std::endl
724 << "There is NO WARRANTY, to the extent permitted by law." << std::endl 732 << "There is NO WARRANTY, to the extent permitted by law." << std::endl
725 << std::endl 733 << std::endl
726 << "Written by Sebastien Jodogne <s.jodogne@orthanc-labs.com>" << std::endl; 734 << "Written by Sebastien Jodogne <s.jodogne@orthanc-labs.com>" << std::endl;
727 } 735 }
1215 { 1223 {
1216 OrthancConfiguration::ReaderLock lock; 1224 OrthancConfiguration::ReaderLock lock;
1217 dicomServer.SetCalledApplicationEntityTitleCheck(lock.GetConfiguration().GetBooleanParameter("DicomCheckCalledAet", false)); 1225 dicomServer.SetCalledApplicationEntityTitleCheck(lock.GetConfiguration().GetBooleanParameter("DicomCheckCalledAet", false));
1218 dicomServer.SetAssociationTimeout(lock.GetConfiguration().GetUnsignedIntegerParameter("DicomScpTimeout", 30)); 1226 dicomServer.SetAssociationTimeout(lock.GetConfiguration().GetUnsignedIntegerParameter("DicomScpTimeout", 30));
1219 dicomServer.SetPortNumber(lock.GetConfiguration().GetUnsignedIntegerParameter("DicomPort", 4242)); 1227 dicomServer.SetPortNumber(lock.GetConfiguration().GetUnsignedIntegerParameter("DicomPort", 4242));
1228 dicomServer.SetThreadsCount(lock.GetConfiguration().GetUnsignedIntegerParameter("DicomThreadsCount", 4));
1220 dicomServer.SetApplicationEntityTitle(lock.GetConfiguration().GetOrthancAET()); 1229 dicomServer.SetApplicationEntityTitle(lock.GetConfiguration().GetOrthancAET());
1221 1230
1222 // Configuration of DICOM TLS for Orthanc SCP (since Orthanc 1.9.0) 1231 // Configuration of DICOM TLS for Orthanc SCP (since Orthanc 1.9.0)
1223 dicomServer.SetDicomTlsEnabled(lock.GetConfiguration().GetBooleanParameter(KEY_DICOM_TLS_ENABLED, false)); 1232 dicomServer.SetDicomTlsEnabled(lock.GetConfiguration().GetBooleanParameter(KEY_DICOM_TLS_ENABLED, false));
1224 if (dicomServer.IsDicomTlsEnabled()) 1233 if (dicomServer.IsDicomTlsEnabled())
1525 context.GetIndex().SetMaximumStorageSize(size * 1024 * 1024); 1534 context.GetIndex().SetMaximumStorageSize(size * 1024 * 1024);
1526 } 1535 }
1527 catch (...) 1536 catch (...)
1528 { 1537 {
1529 context.GetIndex().SetMaximumStorageSize(0); 1538 context.GetIndex().SetMaximumStorageSize(0);
1539 }
1540
1541 try
1542 {
1543 uint64_t size = lock.GetConfiguration().GetUnsignedIntegerParameter("MaximumStorageCacheSize", 128);
1544 context.SetMaximumStorageCacheSize(size * 1024 * 1024);
1545 }
1546 catch (...)
1547 {
1548 context.SetMaximumStorageCacheSize(128);
1530 } 1549 }
1531 } 1550 }
1532 1551
1533 { 1552 {
1534 ServerContextConfigurator configurator(context, plugins); // This calls "OrthancConfiguration::SetServerIndex()" 1553 ServerContextConfigurator configurator(context, plugins); // This calls "OrthancConfiguration::SetServerIndex()"