Mercurial > hg > orthanc
comparison Core/DicomNetworking/DicomUserConnection.cpp @ 3657:115f82775c46 storage-commitment
handling of storage commitment failure reasons
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 10 Feb 2020 14:53:36 +0100 |
parents | f6a73611ec5c |
children | 736907ecb626 |
comparison
equal
deleted
inserted
replaced
3656:cccd97333e3d | 3657:115f82775c46 |
---|---|
1385 } | 1385 } |
1386 | 1386 |
1387 | 1387 |
1388 static void FillSopSequence(DcmDataset& dataset, | 1388 static void FillSopSequence(DcmDataset& dataset, |
1389 const DcmTagKey& tag, | 1389 const DcmTagKey& tag, |
1390 const std::list<std::string>& sopClassUids, | 1390 const std::vector<std::string>& sopClassUids, |
1391 const std::list<std::string>& sopInstanceUids, | 1391 const std::vector<std::string>& sopInstanceUids, |
1392 bool hasFailureReason, | 1392 const std::vector<StorageCommitmentFailureReason>& failureReasons, |
1393 Uint16 failureReason) | 1393 bool hasFailureReasons) |
1394 { | 1394 { |
1395 assert(sopClassUids.size() == sopInstanceUids.size()); | 1395 assert(sopClassUids.size() == sopInstanceUids.size() && |
1396 (hasFailureReasons ? | |
1397 failureReasons.size() == sopClassUids.size() : | |
1398 failureReasons.empty())); | |
1396 | 1399 |
1397 if (sopInstanceUids.empty()) | 1400 if (sopInstanceUids.empty()) |
1398 { | 1401 { |
1399 // Add an empty sequence | 1402 // Add an empty sequence |
1400 if (!dataset.insertEmptyElement(tag).good()) | 1403 if (!dataset.insertEmptyElement(tag).good()) |
1402 throw OrthancException(ErrorCode_InternalError); | 1405 throw OrthancException(ErrorCode_InternalError); |
1403 } | 1406 } |
1404 } | 1407 } |
1405 else | 1408 else |
1406 { | 1409 { |
1407 std::list<std::string>::const_iterator currentClass = sopClassUids.begin(); | 1410 for (size_t i = 0; i < sopClassUids.size(); i++) |
1408 std::list<std::string>::const_iterator currentInstance = sopInstanceUids.begin(); | |
1409 | |
1410 while (currentClass != sopClassUids.end()) | |
1411 { | 1411 { |
1412 std::auto_ptr<DcmItem> item(new DcmItem); | 1412 std::auto_ptr<DcmItem> item(new DcmItem); |
1413 if (!item->putAndInsertString(DCM_ReferencedSOPClassUID, currentClass->c_str()).good() || | 1413 if (!item->putAndInsertString(DCM_ReferencedSOPClassUID, sopClassUids[i].c_str()).good() || |
1414 !item->putAndInsertString(DCM_ReferencedSOPInstanceUID, currentInstance->c_str()).good() || | 1414 !item->putAndInsertString(DCM_ReferencedSOPInstanceUID, sopInstanceUids[i].c_str()).good() || |
1415 (hasFailureReason && | 1415 (hasFailureReasons && |
1416 !item->putAndInsertUint16(DCM_FailureReason, failureReason).good()) || | 1416 !item->putAndInsertUint16(DCM_FailureReason, failureReasons[i]).good()) || |
1417 !dataset.insertSequenceItem(tag, item.release()).good()) | 1417 !dataset.insertSequenceItem(tag, item.release()).good()) |
1418 { | 1418 { |
1419 throw OrthancException(ErrorCode_InternalError); | 1419 throw OrthancException(ErrorCode_InternalError); |
1420 } | 1420 } |
1421 | |
1422 ++currentClass; | |
1423 ++currentInstance; | |
1424 } | |
1425 | |
1426 for (size_t i = 0; i < sopClassUids.size(); i++) | |
1427 { | |
1428 } | 1421 } |
1429 } | 1422 } |
1430 } | 1423 } |
1431 | 1424 |
1432 | 1425 |
1433 | 1426 |
1434 | 1427 |
1435 void DicomUserConnection::ReportStorageCommitment( | 1428 void DicomUserConnection::ReportStorageCommitment( |
1436 const std::string& transactionUid, | 1429 const std::string& transactionUid, |
1437 const std::list<std::string>& successSopClassUids, | 1430 const std::vector<std::string>& sopClassUids, |
1438 const std::list<std::string>& successSopInstanceUids, | 1431 const std::vector<std::string>& sopInstanceUids, |
1439 const std::list<std::string>& failureSopClassUids, | 1432 const std::vector<StorageCommitmentFailureReason>& failureReasons) |
1440 const std::list<std::string>& failureSopInstanceUids) | 1433 { |
1441 { | 1434 if (sopClassUids.size() != sopInstanceUids.size() || |
1442 if (successSopClassUids.size() != successSopInstanceUids.size() || | 1435 sopClassUids.size() != failureReasons.size()) |
1443 failureSopClassUids.size() != failureSopInstanceUids.size()) | |
1444 { | 1436 { |
1445 throw OrthancException(ErrorCode_ParameterOutOfRange); | 1437 throw OrthancException(ErrorCode_ParameterOutOfRange); |
1446 } | 1438 } |
1447 | 1439 |
1448 if (IsOpen()) | 1440 if (IsOpen()) |
1449 { | 1441 { |
1450 Close(); | 1442 Close(); |
1451 } | 1443 } |
1452 | 1444 |
1445 std::vector<std::string> successSopClassUids, successSopInstanceUids, failedSopClassUids, failedSopInstanceUids; | |
1446 std::vector<StorageCommitmentFailureReason> failedReasons; | |
1447 | |
1448 successSopClassUids.reserve(sopClassUids.size()); | |
1449 successSopInstanceUids.reserve(sopClassUids.size()); | |
1450 failedSopClassUids.reserve(sopClassUids.size()); | |
1451 failedSopInstanceUids.reserve(sopClassUids.size()); | |
1452 failedReasons.reserve(sopClassUids.size()); | |
1453 | |
1454 for (size_t i = 0; i < sopClassUids.size(); i++) | |
1455 { | |
1456 switch (failureReasons[i]) | |
1457 { | |
1458 case StorageCommitmentFailureReason_Success: | |
1459 successSopClassUids.push_back(sopClassUids[i]); | |
1460 successSopInstanceUids.push_back(sopInstanceUids[i]); | |
1461 break; | |
1462 | |
1463 case StorageCommitmentFailureReason_ProcessingFailure: | |
1464 case StorageCommitmentFailureReason_NoSuchObjectInstance: | |
1465 case StorageCommitmentFailureReason_ResourceLimitation: | |
1466 case StorageCommitmentFailureReason_ReferencedSOPClassNotSupported: | |
1467 case StorageCommitmentFailureReason_ClassInstanceConflict: | |
1468 case StorageCommitmentFailureReason_DuplicateTransactionUID: | |
1469 failedSopClassUids.push_back(sopClassUids[i]); | |
1470 failedSopInstanceUids.push_back(sopInstanceUids[i]); | |
1471 failedReasons.push_back(failureReasons[i]); | |
1472 break; | |
1473 | |
1474 default: | |
1475 { | |
1476 char buf[16]; | |
1477 sprintf(buf, "%04xH", failureReasons[i]); | |
1478 throw OrthancException(ErrorCode_ParameterOutOfRange, | |
1479 "Unsupported failure reason for storage commitment: " + std::string(buf)); | |
1480 } | |
1481 } | |
1482 } | |
1483 | |
1453 try | 1484 try |
1454 { | 1485 { |
1455 OpenInternal(Mode_ReportStorageCommitment); | 1486 OpenInternal(Mode_ReportStorageCommitment); |
1456 | 1487 |
1457 /** | 1488 /** |
1468 **/ | 1499 **/ |
1469 | 1500 |
1470 LOG(INFO) << "Reporting modality \"" << remoteAet_ | 1501 LOG(INFO) << "Reporting modality \"" << remoteAet_ |
1471 << "\" about storage commitment transaction: " << transactionUid | 1502 << "\" about storage commitment transaction: " << transactionUid |
1472 << " (" << successSopClassUids.size() << " successes, " | 1503 << " (" << successSopClassUids.size() << " successes, " |
1473 << failureSopClassUids.size() << " failures)"; | 1504 << failedSopClassUids.size() << " failures)"; |
1474 const DIC_US messageId = pimpl_->assoc_->nextMsgID++; | 1505 const DIC_US messageId = pimpl_->assoc_->nextMsgID++; |
1475 | 1506 |
1476 { | 1507 { |
1477 T_DIMSE_Message message; | 1508 T_DIMSE_Message message; |
1478 memset(&message, 0, sizeof(message)); | 1509 memset(&message, 0, sizeof(message)); |
1488 if (!dataset.putAndInsertString(DCM_TransactionUID, transactionUid.c_str()).good()) | 1519 if (!dataset.putAndInsertString(DCM_TransactionUID, transactionUid.c_str()).good()) |
1489 { | 1520 { |
1490 throw OrthancException(ErrorCode_InternalError); | 1521 throw OrthancException(ErrorCode_InternalError); |
1491 } | 1522 } |
1492 | 1523 |
1493 FillSopSequence(dataset, DCM_ReferencedSOPSequence, successSopClassUids, | 1524 { |
1494 successSopInstanceUids, false, 0); | 1525 std::vector<StorageCommitmentFailureReason> empty; |
1526 FillSopSequence(dataset, DCM_ReferencedSOPSequence, successSopClassUids, | |
1527 successSopInstanceUids, empty, false); | |
1528 } | |
1495 | 1529 |
1496 // http://dicom.nema.org/medical/dicom/2019a/output/chtml/part04/sect_J.3.3.html | 1530 // http://dicom.nema.org/medical/dicom/2019a/output/chtml/part04/sect_J.3.3.html |
1497 if (failureSopClassUids.empty()) | 1531 if (failedSopClassUids.empty()) |
1498 { | 1532 { |
1499 content.EventTypeID = 1; // "Storage Commitment Request Successful" | 1533 content.EventTypeID = 1; // "Storage Commitment Request Successful" |
1500 } | 1534 } |
1501 else | 1535 else |
1502 { | 1536 { |
1503 content.EventTypeID = 2; // "Storage Commitment Request Complete - Failures Exist" | 1537 content.EventTypeID = 2; // "Storage Commitment Request Complete - Failures Exist" |
1504 | 1538 |
1505 // Failure reason | 1539 // Failure reason |
1506 // http://dicom.nema.org/medical/dicom/2019a/output/chtml/part03/sect_C.14.html#sect_C.14.1.1 | 1540 // http://dicom.nema.org/medical/dicom/2019a/output/chtml/part03/sect_C.14.html#sect_C.14.1.1 |
1507 FillSopSequence(dataset, DCM_FailedSOPSequence, failureSopClassUids, | 1541 FillSopSequence(dataset, DCM_FailedSOPSequence, failedSopClassUids, |
1508 failureSopInstanceUids, true, 0x0112 /* No such object instance == 274 */); | 1542 failedSopInstanceUids, failedReasons, true); |
1509 } | 1543 } |
1510 | 1544 |
1511 int presID = ASC_findAcceptedPresentationContextID( | 1545 int presID = ASC_findAcceptedPresentationContextID( |
1512 pimpl_->assoc_, UID_StorageCommitmentPushModelSOPClass); | 1546 pimpl_->assoc_, UID_StorageCommitmentPushModelSOPClass); |
1513 if (presID == 0) | 1547 if (presID == 0) |
1572 | 1606 |
1573 | 1607 |
1574 | 1608 |
1575 void DicomUserConnection::RequestStorageCommitment( | 1609 void DicomUserConnection::RequestStorageCommitment( |
1576 const std::string& transactionUid, | 1610 const std::string& transactionUid, |
1577 const std::list<std::string>& sopClassUids, | 1611 const std::vector<std::string>& sopClassUids, |
1578 const std::list<std::string>& sopInstanceUids) | 1612 const std::vector<std::string>& sopInstanceUids) |
1579 { | 1613 { |
1580 if (sopClassUids.size() != sopInstanceUids.size()) | 1614 if (sopClassUids.size() != sopInstanceUids.size()) |
1581 { | 1615 { |
1582 throw OrthancException(ErrorCode_ParameterOutOfRange); | 1616 throw OrthancException(ErrorCode_ParameterOutOfRange); |
1583 } | 1617 } |
1631 if (!dataset.putAndInsertString(DCM_TransactionUID, transactionUid.c_str()).good()) | 1665 if (!dataset.putAndInsertString(DCM_TransactionUID, transactionUid.c_str()).good()) |
1632 { | 1666 { |
1633 throw OrthancException(ErrorCode_InternalError); | 1667 throw OrthancException(ErrorCode_InternalError); |
1634 } | 1668 } |
1635 | 1669 |
1636 FillSopSequence(dataset, DCM_ReferencedSOPSequence, sopClassUids, sopInstanceUids, false, 0); | 1670 { |
1637 | 1671 std::vector<StorageCommitmentFailureReason> empty; |
1672 FillSopSequence(dataset, DCM_ReferencedSOPSequence, sopClassUids, sopInstanceUids, empty, false); | |
1673 } | |
1674 | |
1638 int presID = ASC_findAcceptedPresentationContextID( | 1675 int presID = ASC_findAcceptedPresentationContextID( |
1639 pimpl_->assoc_, UID_StorageCommitmentPushModelSOPClass); | 1676 pimpl_->assoc_, UID_StorageCommitmentPushModelSOPClass); |
1640 if (presID == 0) | 1677 if (presID == 0) |
1641 { | 1678 { |
1642 throw OrthancException(ErrorCode_NetworkProtocol, "Storage commitment - " | 1679 throw OrthancException(ErrorCode_NetworkProtocol, "Storage commitment - " |