Mercurial > hg > orthanc
comparison OrthancFramework/Sources/DicomNetworking/Internals/CommandDispatcher.cpp @ 4468:9c070a34de18
IApplicationEntityFilter::GetAcceptedTransferSyntaxes()
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 25 Jan 2021 15:18:34 +0100 |
parents | f4dbdb2dcba6 |
children | 68f52897c119 |
comparison
equal
deleted
inserted
replaced
4467:c92ec129698a | 4468:9c070a34de18 |
---|---|
407 } | 407 } |
408 | 408 |
409 | 409 |
410 { | 410 { |
411 /* accept the abstract syntaxes for C-STORE, if presented */ | 411 /* accept the abstract syntaxes for C-STORE, if presented */ |
412 | 412 |
413 std::vector<const char*> storageTransferSyntaxes; | 413 std::set<DicomTransferSyntax> storageTransferSyntaxes; |
414 | 414 |
415 // This is the list of the transfer syntaxes that were supported up to Orthanc 0.7.1 | 415 if (server.HasApplicationEntityFilter()) |
416 storageTransferSyntaxes.push_back(UID_LittleEndianExplicitTransferSyntax); | 416 { |
417 storageTransferSyntaxes.push_back(UID_BigEndianExplicitTransferSyntax); | 417 server.GetApplicationEntityFilter().GetAcceptedTransferSyntaxes( |
418 storageTransferSyntaxes.push_back(UID_LittleEndianImplicitTransferSyntax); | 418 storageTransferSyntaxes, remoteIp, remoteAet, calledAet); |
419 | 419 } |
420 // New transfer syntaxes supported since Orthanc 0.7.2 | 420 else |
421 if (!server.HasApplicationEntityFilter() || | 421 { |
422 server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Deflated)) | 422 /** |
423 { | 423 * In the absence of filter, accept all the known transfer |
424 storageTransferSyntaxes.push_back(UID_DeflatedExplicitVRLittleEndianTransferSyntax); | 424 * syntaxes. Note that this is different from Orthanc |
425 } | 425 * framework <= 1.8.2, where only the uncompressed transfer |
426 | 426 * syntaxes are accepted by default. |
427 if (!server.HasApplicationEntityFilter() || | 427 **/ |
428 server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Jpeg)) | 428 GetAllTransferSyntaxes(storageTransferSyntaxes); |
429 { | 429 } |
430 storageTransferSyntaxes.push_back(UID_JPEGProcess1TransferSyntax); | 430 |
431 storageTransferSyntaxes.push_back(UID_JPEGProcess2_4TransferSyntax); | 431 if (storageTransferSyntaxes.empty()) |
432 storageTransferSyntaxes.push_back(UID_JPEGProcess3_5TransferSyntax); | 432 { |
433 storageTransferSyntaxes.push_back(UID_JPEGProcess6_8TransferSyntax); | 433 LOG(WARNING) << "The DICOM server accepts no transfer syntax, thus C-STORE SCP is disabled"; |
434 storageTransferSyntaxes.push_back(UID_JPEGProcess7_9TransferSyntax); | 434 } |
435 storageTransferSyntaxes.push_back(UID_JPEGProcess10_12TransferSyntax); | 435 else |
436 storageTransferSyntaxes.push_back(UID_JPEGProcess11_13TransferSyntax); | 436 { |
437 storageTransferSyntaxes.push_back(UID_JPEGProcess14TransferSyntax); | 437 /** |
438 storageTransferSyntaxes.push_back(UID_JPEGProcess15TransferSyntax); | 438 * If accepted, put "Little Endian Explicit" at the first |
439 storageTransferSyntaxes.push_back(UID_JPEGProcess16_18TransferSyntax); | 439 * place in the accepted transfer syntaxes. This first place |
440 storageTransferSyntaxes.push_back(UID_JPEGProcess17_19TransferSyntax); | 440 * has an impact on the result of "getscu" (cf. integration |
441 storageTransferSyntaxes.push_back(UID_JPEGProcess20_22TransferSyntax); | 441 * test "test_getscu"). We choose "Little Endian Explicit", |
442 storageTransferSyntaxes.push_back(UID_JPEGProcess21_23TransferSyntax); | 442 * as this preserves the VR of the private tags, even if the |
443 storageTransferSyntaxes.push_back(UID_JPEGProcess24_26TransferSyntax); | 443 * remote modality doesn't have the dictionary of private tags. |
444 storageTransferSyntaxes.push_back(UID_JPEGProcess25_27TransferSyntax); | 444 * |
445 storageTransferSyntaxes.push_back(UID_JPEGProcess28TransferSyntax); | 445 * TODO - Should "PREFERRED_TRANSFER_SYNTAX" be an option of |
446 storageTransferSyntaxes.push_back(UID_JPEGProcess29TransferSyntax); | 446 * class "DicomServer"? |
447 storageTransferSyntaxes.push_back(UID_JPEGProcess14SV1TransferSyntax); | 447 **/ |
448 } | 448 const DicomTransferSyntax PREFERRED_TRANSFER_SYNTAX = DicomTransferSyntax_LittleEndianExplicit; |
449 | 449 |
450 if (!server.HasApplicationEntityFilter() || | 450 std::vector<const char*> storageTransferSyntaxesC; |
451 server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Jpeg2000)) | 451 storageTransferSyntaxesC.reserve(storageTransferSyntaxes.size()); |
452 { | 452 |
453 storageTransferSyntaxes.push_back(UID_JPEG2000LosslessOnlyTransferSyntax); | 453 if (storageTransferSyntaxes.find(PREFERRED_TRANSFER_SYNTAX) != storageTransferSyntaxes.end()) |
454 storageTransferSyntaxes.push_back(UID_JPEG2000TransferSyntax); | 454 { |
455 storageTransferSyntaxes.push_back(UID_JPEG2000LosslessOnlyTransferSyntax); | 455 storageTransferSyntaxesC.push_back(GetTransferSyntaxUid(PREFERRED_TRANSFER_SYNTAX)); |
456 storageTransferSyntaxes.push_back(UID_JPEG2000TransferSyntax); | 456 } |
457 storageTransferSyntaxes.push_back(UID_JPEG2000Part2MulticomponentImageCompressionLosslessOnlyTransferSyntax); | 457 |
458 storageTransferSyntaxes.push_back(UID_JPEG2000Part2MulticomponentImageCompressionTransferSyntax); | 458 for (std::set<DicomTransferSyntax>::const_iterator |
459 } | 459 it = storageTransferSyntaxes.begin(); it != storageTransferSyntaxes.end(); ++it) |
460 | 460 { |
461 if (!server.HasApplicationEntityFilter() || | 461 if (*it != PREFERRED_TRANSFER_SYNTAX) // Don't add the preferred transfer syntax twice |
462 server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_JpegLossless)) | 462 { |
463 { | 463 storageTransferSyntaxesC.push_back(GetTransferSyntaxUid(*it)); |
464 storageTransferSyntaxes.push_back(UID_JPEGLSLosslessTransferSyntax); | 464 } |
465 storageTransferSyntaxes.push_back(UID_JPEGLSLossyTransferSyntax); | 465 } |
466 } | 466 |
467 | 467 /* the array of Storage SOP Class UIDs that is defined within "dcmdata/libsrc/dcuid.cc" */ |
468 if (!server.HasApplicationEntityFilter() || | 468 size_t count = 0; |
469 server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Jpip)) | 469 while (dcmAllStorageSOPClassUIDs[count] != NULL) |
470 { | 470 { |
471 storageTransferSyntaxes.push_back(UID_JPIPReferencedTransferSyntax); | 471 count++; |
472 storageTransferSyntaxes.push_back(UID_JPIPReferencedDeflateTransferSyntax); | 472 } |
473 } | |
474 | |
475 if (!server.HasApplicationEntityFilter() || | |
476 server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Mpeg2)) | |
477 { | |
478 storageTransferSyntaxes.push_back(UID_MPEG2MainProfileAtMainLevelTransferSyntax); | |
479 storageTransferSyntaxes.push_back(UID_MPEG2MainProfileAtHighLevelTransferSyntax); | |
480 } | |
481 | |
482 #if DCMTK_VERSION_NUMBER >= 361 | |
483 // New in Orthanc 1.6.0 | |
484 if (!server.HasApplicationEntityFilter() || | |
485 server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Mpeg4)) | |
486 { | |
487 storageTransferSyntaxes.push_back(UID_MPEG4BDcompatibleHighProfileLevel4_1TransferSyntax); | |
488 storageTransferSyntaxes.push_back(UID_MPEG4HighProfileLevel4_1TransferSyntax); | |
489 storageTransferSyntaxes.push_back(UID_MPEG4HighProfileLevel4_2_For2DVideoTransferSyntax); | |
490 storageTransferSyntaxes.push_back(UID_MPEG4HighProfileLevel4_2_For3DVideoTransferSyntax); | |
491 storageTransferSyntaxes.push_back(UID_MPEG4StereoHighProfileLevel4_2TransferSyntax); | |
492 } | |
493 #endif | |
494 | |
495 if (!server.HasApplicationEntityFilter() || | |
496 server.GetApplicationEntityFilter().IsAllowedTransferSyntax(remoteIp, remoteAet, calledAet, TransferSyntax_Rle)) | |
497 { | |
498 storageTransferSyntaxes.push_back(UID_RLELosslessTransferSyntax); | |
499 } | |
500 | |
501 /* the array of Storage SOP Class UIDs that is defined within "dcmdata/libsrc/dcuid.cc" */ | |
502 size_t count = 0; | |
503 while (dcmAllStorageSOPClassUIDs[count] != NULL) | |
504 { | |
505 count++; | |
506 } | |
507 | 473 |
508 #if DCMTK_VERSION_NUMBER >= 362 | 474 #if DCMTK_VERSION_NUMBER >= 362 |
509 // The global variable "numberOfDcmAllStorageSOPClassUIDs" is | 475 // The global variable "numberOfDcmAllStorageSOPClassUIDs" is |
510 // only published if DCMTK >= 3.6.2: | 476 // only published if DCMTK >= 3.6.2: |
511 // https://bitbucket.org/sjodogne/orthanc/issues/137 | 477 // https://bitbucket.org/sjodogne/orthanc/issues/137 |
512 assert(static_cast<int>(count) == numberOfDcmAllStorageSOPClassUIDs); | 478 assert(static_cast<int>(count) == numberOfDcmAllStorageSOPClassUIDs); |
513 #endif | 479 #endif |
514 | 480 |
515 if (!server.HasGetRequestHandlerFactory()) // dcmqrsrv.cc line 828 | 481 if (!server.HasGetRequestHandlerFactory()) // dcmqrsrv.cc line 828 |
516 { | |
517 // This branch exactly corresponds to Orthanc <= 1.6.1 (in | |
518 // which C-GET SCP was not supported) | |
519 cond = ASC_acceptContextsWithPreferredTransferSyntaxes( | |
520 assoc->params, dcmAllStorageSOPClassUIDs, count, | |
521 &storageTransferSyntaxes[0], storageTransferSyntaxes.size()); | |
522 if (cond.bad()) | |
523 { | 482 { |
524 CLOG(INFO, DICOM) << cond.text(); | 483 // This branch exactly corresponds to Orthanc <= 1.6.1 (in |
525 AssociationCleanup(assoc); | 484 // which C-GET SCP was not supported) |
526 return NULL; | 485 cond = ASC_acceptContextsWithPreferredTransferSyntaxes( |
486 assoc->params, dcmAllStorageSOPClassUIDs, count, | |
487 &storageTransferSyntaxesC[0], storageTransferSyntaxesC.size()); | |
488 if (cond.bad()) | |
489 { | |
490 CLOG(INFO, DICOM) << cond.text(); | |
491 AssociationCleanup(assoc); | |
492 return NULL; | |
493 } | |
527 } | 494 } |
528 } | 495 else // see dcmqrsrv.cc lines 839 - 876 |
529 else // see dcmqrsrv.cc lines 839 - 876 | |
530 { | |
531 /* accept storage syntaxes with proposed role */ | |
532 int npc = ASC_countPresentationContexts(assoc->params); | |
533 for (int i = 0; i < npc; i++) | |
534 { | 496 { |
535 T_ASC_PresentationContext pc; | 497 /* accept storage syntaxes with proposed role */ |
536 ASC_getPresentationContext(assoc->params, i, &pc); | 498 int npc = ASC_countPresentationContexts(assoc->params); |
537 if (dcmIsaStorageSOPClassUID(pc.abstractSyntax)) | 499 for (int i = 0; i < npc; i++) |
538 { | 500 { |
539 /** | 501 T_ASC_PresentationContext pc; |
540 * We are prepared to accept whatever role the caller | 502 ASC_getPresentationContext(assoc->params, i, &pc); |
541 * proposes. Normally we can be the SCP of the Storage | 503 if (dcmIsaStorageSOPClassUID(pc.abstractSyntax)) |
542 * Service Class. When processing the C-GET operation | 504 { |
543 * we can be the SCU of the Storage Service Class. | 505 /** |
544 **/ | 506 * We are prepared to accept whatever role the caller |
545 const T_ASC_SC_ROLE role = pc.proposedRole; | 507 * proposes. Normally we can be the SCP of the Storage |
508 * Service Class. When processing the C-GET operation | |
509 * we can be the SCU of the Storage Service Class. | |
510 **/ | |
511 const T_ASC_SC_ROLE role = pc.proposedRole; | |
546 | 512 |
547 /** | 513 /** |
548 * Accept in the order "least wanted" to "most wanted" | 514 * Accept in the order "least wanted" to "most wanted" |
549 * transfer syntax. Accepting a transfer syntax will | 515 * transfer syntax. Accepting a transfer syntax will |
550 * override previously accepted transfer syntaxes. | 516 * override previously accepted transfer syntaxes. |
551 **/ | 517 **/ |
552 for (int k = static_cast<int>(storageTransferSyntaxes.size()) - 1; k >= 0; k--) | 518 for (int k = static_cast<int>(storageTransferSyntaxesC.size()) - 1; k >= 0; k--) |
553 { | |
554 for (int j = 0; j < static_cast<int>(pc.transferSyntaxCount); j++) | |
555 { | 519 { |
556 /** | 520 for (int j = 0; j < static_cast<int>(pc.transferSyntaxCount); j++) |
557 * If the transfer syntax was proposed then we can accept it | |
558 * appears in our supported list of transfer syntaxes | |
559 **/ | |
560 if (strcmp(pc.proposedTransferSyntaxes[j], storageTransferSyntaxes[k]) == 0) | |
561 { | 521 { |
562 cond = ASC_acceptPresentationContext( | 522 /** |
563 assoc->params, pc.presentationContextID, storageTransferSyntaxes[k], role); | 523 * If the transfer syntax was proposed then we can accept it |
564 if (cond.bad()) | 524 * appears in our supported list of transfer syntaxes |
525 **/ | |
526 if (strcmp(pc.proposedTransferSyntaxes[j], storageTransferSyntaxesC[k]) == 0) | |
565 { | 527 { |
566 CLOG(INFO, DICOM) << cond.text(); | 528 cond = ASC_acceptPresentationContext( |
567 AssociationCleanup(assoc); | 529 assoc->params, pc.presentationContextID, storageTransferSyntaxesC[k], role); |
568 return NULL; | 530 if (cond.bad()) |
531 { | |
532 CLOG(INFO, DICOM) << cond.text(); | |
533 AssociationCleanup(assoc); | |
534 return NULL; | |
535 } | |
569 } | 536 } |
570 } | 537 } |
571 } | 538 } |
572 } | 539 } |
540 } /* for */ | |
541 } | |
542 | |
543 if (!server.HasApplicationEntityFilter() || | |
544 server.GetApplicationEntityFilter().IsUnknownSopClassAccepted(remoteIp, remoteAet, calledAet)) | |
545 { | |
546 /* | |
547 * Promiscous mode is enabled: Accept everything not known not | |
548 * to be a storage SOP class. | |
549 **/ | |
550 cond = acceptUnknownContextsWithPreferredTransferSyntaxes( | |
551 assoc->params, &storageTransferSyntaxesC[0], storageTransferSyntaxesC.size(), ASC_SC_ROLE_DEFAULT); | |
552 if (cond.bad()) | |
553 { | |
554 CLOG(INFO, DICOM) << cond.text(); | |
555 AssociationCleanup(assoc); | |
556 return NULL; | |
573 } | 557 } |
574 } /* for */ | |
575 } | |
576 | |
577 if (!server.HasApplicationEntityFilter() || | |
578 server.GetApplicationEntityFilter().IsUnknownSopClassAccepted(remoteIp, remoteAet, calledAet)) | |
579 { | |
580 /* | |
581 * Promiscous mode is enabled: Accept everything not known not | |
582 * to be a storage SOP class. | |
583 **/ | |
584 cond = acceptUnknownContextsWithPreferredTransferSyntaxes( | |
585 assoc->params, &storageTransferSyntaxes[0], storageTransferSyntaxes.size(), ASC_SC_ROLE_DEFAULT); | |
586 if (cond.bad()) | |
587 { | |
588 CLOG(INFO, DICOM) << cond.text(); | |
589 AssociationCleanup(assoc); | |
590 return NULL; | |
591 } | 558 } |
592 } | 559 } |
593 } | 560 } |
594 | 561 |
595 /* set our app title */ | 562 /* set our app title */ |