comparison OrthancServer/Internals/CommandDispatcher.cpp @ 1163:3db41779d8f9

abstraction to allow/prevent transfer syntaxes on AET basis
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 17 Sep 2014 17:23:08 +0200
parents b161593551db
children 0a55d8eb194e
comparison
equal deleted inserted replaced
1160:80671157d051 1163:3db41779d8f9
457 // no matter what kind of error occurred, we need to do a cleanup 457 // no matter what kind of error occurred, we need to do a cleanup
458 AssociationCleanup(assoc); 458 AssociationCleanup(assoc);
459 return NULL; 459 return NULL;
460 } 460 }
461 461
462 LOG(INFO) << "Association Received"; 462 // Retrieve the AET and the IP address of the remote modality
463 463 std::string callingAet;
464 std::vector<const char*> transferSyntaxes;
465
466 // This is the list of the transfer syntaxes that were supported up to Orthanc 0.7.1
467 transferSyntaxes.push_back(UID_LittleEndianExplicitTransferSyntax);
468 transferSyntaxes.push_back(UID_BigEndianExplicitTransferSyntax);
469 transferSyntaxes.push_back(UID_LittleEndianImplicitTransferSyntax);
470
471 // New transfer syntaxes supported since Orthanc 0.7.2
472 transferSyntaxes.push_back(UID_DeflatedExplicitVRLittleEndianTransferSyntax);
473 transferSyntaxes.push_back(UID_JPEGProcess1TransferSyntax);
474 transferSyntaxes.push_back(UID_JPEGProcess2_4TransferSyntax);
475 transferSyntaxes.push_back(UID_JPEGProcess3_5TransferSyntax);
476 transferSyntaxes.push_back(UID_JPEGProcess6_8TransferSyntax);
477 transferSyntaxes.push_back(UID_JPEGProcess7_9TransferSyntax);
478 transferSyntaxes.push_back(UID_JPEGProcess10_12TransferSyntax);
479 transferSyntaxes.push_back(UID_JPEGProcess11_13TransferSyntax);
480 transferSyntaxes.push_back(UID_JPEGProcess14TransferSyntax);
481 transferSyntaxes.push_back(UID_JPEGProcess15TransferSyntax);
482 transferSyntaxes.push_back(UID_JPEGProcess16_18TransferSyntax);
483 transferSyntaxes.push_back(UID_JPEGProcess17_19TransferSyntax);
484 transferSyntaxes.push_back(UID_JPEGProcess20_22TransferSyntax);
485 transferSyntaxes.push_back(UID_JPEGProcess21_23TransferSyntax);
486 transferSyntaxes.push_back(UID_JPEGProcess24_26TransferSyntax);
487 transferSyntaxes.push_back(UID_JPEGProcess25_27TransferSyntax);
488 transferSyntaxes.push_back(UID_JPEGProcess28TransferSyntax);
489 transferSyntaxes.push_back(UID_JPEGProcess29TransferSyntax);
490 transferSyntaxes.push_back(UID_JPEGProcess14SV1TransferSyntax);
491 transferSyntaxes.push_back(UID_JPEGLSLosslessTransferSyntax);
492 transferSyntaxes.push_back(UID_JPEGLSLossyTransferSyntax);
493 transferSyntaxes.push_back(UID_JPEG2000LosslessOnlyTransferSyntax);
494 transferSyntaxes.push_back(UID_JPEG2000TransferSyntax);
495 transferSyntaxes.push_back(UID_JPEG2000Part2MulticomponentImageCompressionLosslessOnlyTransferSyntax);
496 transferSyntaxes.push_back(UID_JPEG2000Part2MulticomponentImageCompressionTransferSyntax);
497 transferSyntaxes.push_back(UID_JPIPReferencedTransferSyntax);
498 transferSyntaxes.push_back(UID_JPIPReferencedDeflateTransferSyntax);
499 transferSyntaxes.push_back(UID_MPEG2MainProfileAtMainLevelTransferSyntax);
500 transferSyntaxes.push_back(UID_MPEG2MainProfileAtHighLevelTransferSyntax);
501 transferSyntaxes.push_back(UID_RLELosslessTransferSyntax);
502
503 /* accept the Verification SOP Class if presented */
504 cond = ASC_acceptContextsWithPreferredTransferSyntaxes(assoc->params, &knownAbstractSyntaxes[0], knownAbstractSyntaxes.size(), &transferSyntaxes[0], transferSyntaxes.size());
505 if (cond.bad())
506 {
507 LOG(INFO) << cond.text();
508 AssociationCleanup(assoc);
509 return NULL;
510 }
511
512 /* the array of Storage SOP Class UIDs comes from dcuid.h */
513 cond = ASC_acceptContextsWithPreferredTransferSyntaxes(assoc->params, orthancStorageSOPClassUIDs, orthancStorageSOPClassUIDsCount, &transferSyntaxes[0], transferSyntaxes.size());
514 if (cond.bad())
515 {
516 LOG(INFO) << cond.text();
517 AssociationCleanup(assoc);
518 return NULL;
519 }
520
521 #if ORTHANC_PROMISCUOUS == 1
522 /* accept everything not known not to be a storage SOP class */
523 cond = acceptUnknownContextsWithPreferredTransferSyntaxes(
524 assoc->params, &transferSyntaxes[0], transferSyntaxes.size());
525 if (cond.bad())
526 {
527 LOG(INFO) << cond.text();
528 AssociationCleanup(assoc);
529 return NULL;
530 }
531 #endif
532
533 /* set our app title */
534 ASC_setAPTitles(assoc->params, NULL, NULL, server.GetApplicationEntityTitle().c_str());
535
536 /* acknowledge or reject this association */
537 cond = ASC_getApplicationContextName(assoc->params, buf);
538 if ((cond.bad()) || strcmp(buf, UID_StandardApplicationContext) != 0)
539 {
540 /* reject: the application context name is not supported */
541 T_ASC_RejectParameters rej =
542 {
543 ASC_RESULT_REJECTEDPERMANENT,
544 ASC_SOURCE_SERVICEUSER,
545 ASC_REASON_SU_APPCONTEXTNAMENOTSUPPORTED
546 };
547
548 LOG(INFO) << "Association Rejected: Bad Application Context Name: " << buf;
549 cond = ASC_rejectAssociation(assoc, &rej);
550 if (cond.bad())
551 {
552 LOG(INFO) << cond.text();
553 }
554 AssociationCleanup(assoc);
555 return NULL;
556 }
557
558 std::string callingIP; 464 std::string callingIP;
559 std::string callingTitle; 465 std::string calledAet;
560 466
561 /* check the AETs */ 467 {
562 { 468 DIC_AE callingAet_C;
563 DIC_AE callingTitle_C; 469 DIC_AE calledAet_C;
564 DIC_AE calledTitle_C;
565 DIC_AE callingIP_C; 470 DIC_AE callingIP_C;
566 DIC_AE calledIP_C; 471 DIC_AE calledIP_C;
567 if (ASC_getAPTitles(assoc->params, callingTitle_C, calledTitle_C, NULL).bad() || 472 if (ASC_getAPTitles(assoc->params, callingAet_C, calledAet_C, NULL).bad() ||
568 ASC_getPresentationAddresses(assoc->params, callingIP_C, calledIP_C).bad()) 473 ASC_getPresentationAddresses(assoc->params, callingIP_C, calledIP_C).bad())
569 { 474 {
570 T_ASC_RejectParameters rej = 475 T_ASC_RejectParameters rej =
571 { 476 {
572 ASC_RESULT_REJECTEDPERMANENT, 477 ASC_RESULT_REJECTEDPERMANENT,
577 AssociationCleanup(assoc); 482 AssociationCleanup(assoc);
578 return NULL; 483 return NULL;
579 } 484 }
580 485
581 callingIP = std::string(/*OFSTRING_GUARD*/(callingIP_C)); 486 callingIP = std::string(/*OFSTRING_GUARD*/(callingIP_C));
582 callingTitle = std::string(/*OFSTRING_GUARD*/(callingTitle_C)); 487 callingAet = std::string(/*OFSTRING_GUARD*/(callingAet_C));
583 std::string calledTitle(/*OFSTRING_GUARD*/(calledTitle_C)); 488 calledAet = (/*OFSTRING_GUARD*/(calledAet_C));
584 489 }
585 if (!server.IsMyAETitle(calledTitle)) 490
586 { 491 LOG(INFO) << "Association Received from AET " << callingAet
587 T_ASC_RejectParameters rej = 492 << " on IP " << callingIP;
588 { 493
589 ASC_RESULT_REJECTEDPERMANENT, 494
590 ASC_SOURCE_SERVICEUSER, 495 std::vector<const char*> transferSyntaxes;
591 ASC_REASON_SU_CALLEDAETITLENOTRECOGNIZED 496
592 }; 497 // This is the list of the transfer syntaxes that were supported up to Orthanc 0.7.1
593 ASC_rejectAssociation(assoc, &rej); 498 transferSyntaxes.push_back(UID_LittleEndianExplicitTransferSyntax);
594 AssociationCleanup(assoc); 499 transferSyntaxes.push_back(UID_BigEndianExplicitTransferSyntax);
595 return NULL; 500 transferSyntaxes.push_back(UID_LittleEndianImplicitTransferSyntax);
596 } 501
597 502 // New transfer syntaxes supported since Orthanc 0.7.2
598 if (server.HasApplicationEntityFilter() && 503 if (!server.HasApplicationEntityFilter() ||
599 !server.GetApplicationEntityFilter().IsAllowedConnection(callingIP, callingTitle)) 504 server.GetApplicationEntityFilter().IsAllowedTransferSyntax(callingAet, TransferSyntax_Deflated))
600 { 505 {
601 T_ASC_RejectParameters rej = 506 transferSyntaxes.push_back(UID_DeflatedExplicitVRLittleEndianTransferSyntax);
602 { 507 }
603 ASC_RESULT_REJECTEDPERMANENT, 508
604 ASC_SOURCE_SERVICEUSER, 509 if (!server.HasApplicationEntityFilter() ||
605 ASC_REASON_SU_CALLINGAETITLENOTRECOGNIZED 510 server.GetApplicationEntityFilter().IsAllowedTransferSyntax(callingAet, TransferSyntax_Jpeg))
606 }; 511 {
607 ASC_rejectAssociation(assoc, &rej); 512 transferSyntaxes.push_back(UID_JPEGProcess1TransferSyntax);
608 AssociationCleanup(assoc); 513 transferSyntaxes.push_back(UID_JPEGProcess2_4TransferSyntax);
609 return NULL; 514 transferSyntaxes.push_back(UID_JPEGProcess3_5TransferSyntax);
610 } 515 transferSyntaxes.push_back(UID_JPEGProcess6_8TransferSyntax);
611 } 516 transferSyntaxes.push_back(UID_JPEGProcess7_9TransferSyntax);
612 517 transferSyntaxes.push_back(UID_JPEGProcess10_12TransferSyntax);
613 if (opt_rejectWithoutImplementationUID && strlen(assoc->params->theirImplementationClassUID) == 0) 518 transferSyntaxes.push_back(UID_JPEGProcess11_13TransferSyntax);
519 transferSyntaxes.push_back(UID_JPEGProcess14TransferSyntax);
520 transferSyntaxes.push_back(UID_JPEGProcess15TransferSyntax);
521 transferSyntaxes.push_back(UID_JPEGProcess16_18TransferSyntax);
522 transferSyntaxes.push_back(UID_JPEGProcess17_19TransferSyntax);
523 transferSyntaxes.push_back(UID_JPEGProcess20_22TransferSyntax);
524 transferSyntaxes.push_back(UID_JPEGProcess21_23TransferSyntax);
525 transferSyntaxes.push_back(UID_JPEGProcess24_26TransferSyntax);
526 transferSyntaxes.push_back(UID_JPEGProcess25_27TransferSyntax);
527 transferSyntaxes.push_back(UID_JPEGProcess28TransferSyntax);
528 transferSyntaxes.push_back(UID_JPEGProcess29TransferSyntax);
529 transferSyntaxes.push_back(UID_JPEGProcess14SV1TransferSyntax);
530 transferSyntaxes.push_back(UID_JPEGLSLosslessTransferSyntax);
531 transferSyntaxes.push_back(UID_JPEGLSLossyTransferSyntax);
532 }
533
534 if (!server.HasApplicationEntityFilter() ||
535 server.GetApplicationEntityFilter().IsAllowedTransferSyntax(callingAet, TransferSyntax_Jpeg2000))
536 {
537 transferSyntaxes.push_back(UID_JPEG2000LosslessOnlyTransferSyntax);
538 transferSyntaxes.push_back(UID_JPEG2000TransferSyntax);
539 }
540
541 if (!server.HasApplicationEntityFilter() ||
542 server.GetApplicationEntityFilter().IsAllowedTransferSyntax(callingAet, TransferSyntax_JpegLossless))
543 {
544 transferSyntaxes.push_back(UID_JPEG2000LosslessOnlyTransferSyntax);
545 transferSyntaxes.push_back(UID_JPEG2000TransferSyntax);
546 transferSyntaxes.push_back(UID_JPEG2000Part2MulticomponentImageCompressionLosslessOnlyTransferSyntax);
547 transferSyntaxes.push_back(UID_JPEG2000Part2MulticomponentImageCompressionTransferSyntax);
548 }
549
550 if (!server.HasApplicationEntityFilter() ||
551 server.GetApplicationEntityFilter().IsAllowedTransferSyntax(callingAet, TransferSyntax_Jpip))
552 {
553 transferSyntaxes.push_back(UID_JPIPReferencedTransferSyntax);
554 transferSyntaxes.push_back(UID_JPIPReferencedDeflateTransferSyntax);
555 }
556
557 if (!server.HasApplicationEntityFilter() ||
558 server.GetApplicationEntityFilter().IsAllowedTransferSyntax(callingAet, TransferSyntax_Mpeg2))
559 {
560 transferSyntaxes.push_back(UID_MPEG2MainProfileAtMainLevelTransferSyntax);
561 transferSyntaxes.push_back(UID_MPEG2MainProfileAtHighLevelTransferSyntax);
562 }
563
564 if (!server.HasApplicationEntityFilter() ||
565 server.GetApplicationEntityFilter().IsAllowedTransferSyntax(callingAet, TransferSyntax_Rle))
566 {
567 transferSyntaxes.push_back(UID_RLELosslessTransferSyntax);
568 }
569
570 /* accept the Verification SOP Class if presented */
571 cond = ASC_acceptContextsWithPreferredTransferSyntaxes(assoc->params, &knownAbstractSyntaxes[0], knownAbstractSyntaxes.size(), &transferSyntaxes[0], transferSyntaxes.size());
572 if (cond.bad())
573 {
574 LOG(INFO) << cond.text();
575 AssociationCleanup(assoc);
576 return NULL;
577 }
578
579 /* the array of Storage SOP Class UIDs comes from dcuid.h */
580 cond = ASC_acceptContextsWithPreferredTransferSyntaxes(assoc->params, orthancStorageSOPClassUIDs, orthancStorageSOPClassUIDsCount, &transferSyntaxes[0], transferSyntaxes.size());
581 if (cond.bad())
582 {
583 LOG(INFO) << cond.text();
584 AssociationCleanup(assoc);
585 return NULL;
586 }
587
588 #if ORTHANC_PROMISCUOUS == 1
589 /* accept everything not known not to be a storage SOP class */
590 cond = acceptUnknownContextsWithPreferredTransferSyntaxes(
591 assoc->params, &transferSyntaxes[0], transferSyntaxes.size());
592 if (cond.bad())
593 {
594 LOG(INFO) << cond.text();
595 AssociationCleanup(assoc);
596 return NULL;
597 }
598 #endif
599
600 /* set our app title */
601 ASC_setAPTitles(assoc->params, NULL, NULL, server.GetApplicationEntityTitle().c_str());
602
603 /* acknowledge or reject this association */
604 cond = ASC_getApplicationContextName(assoc->params, buf);
605 if ((cond.bad()) || strcmp(buf, UID_StandardApplicationContext) != 0)
606 {
607 /* reject: the application context name is not supported */
608 T_ASC_RejectParameters rej =
609 {
610 ASC_RESULT_REJECTEDPERMANENT,
611 ASC_SOURCE_SERVICEUSER,
612 ASC_REASON_SU_APPCONTEXTNAMENOTSUPPORTED
613 };
614
615 LOG(INFO) << "Association Rejected: Bad Application Context Name: " << buf;
616 cond = ASC_rejectAssociation(assoc, &rej);
617 if (cond.bad())
618 {
619 LOG(INFO) << cond.text();
620 }
621 AssociationCleanup(assoc);
622 return NULL;
623 }
624
625 /* check the AETs */
626 if (!server.IsMyAETitle(calledAet))
627 {
628 LOG(WARNING) << "Rejected association, because of a bad called AET in the request (" << calledAet << ")";
629 T_ASC_RejectParameters rej =
630 {
631 ASC_RESULT_REJECTEDPERMANENT,
632 ASC_SOURCE_SERVICEUSER,
633 ASC_REASON_SU_CALLEDAETITLENOTRECOGNIZED
634 };
635 ASC_rejectAssociation(assoc, &rej);
636 AssociationCleanup(assoc);
637 return NULL;
638 }
639
640 if (server.HasApplicationEntityFilter() &&
641 !server.GetApplicationEntityFilter().IsAllowedConnection(callingIP, callingAet))
642 {
643 LOG(WARNING) << "Rejected association for remote AET " << callingAet << " on IP " << callingIP;
644 T_ASC_RejectParameters rej =
645 {
646 ASC_RESULT_REJECTEDPERMANENT,
647 ASC_SOURCE_SERVICEUSER,
648 ASC_REASON_SU_CALLINGAETITLENOTRECOGNIZED
649 };
650 ASC_rejectAssociation(assoc, &rej);
651 AssociationCleanup(assoc);
652 return NULL;
653 }
654
655 if (opt_rejectWithoutImplementationUID &&
656 strlen(assoc->params->theirImplementationClassUID) == 0)
614 { 657 {
615 /* reject: the no implementation Class UID provided */ 658 /* reject: the no implementation Class UID provided */
616 T_ASC_RejectParameters rej = 659 T_ASC_RejectParameters rej =
617 { 660 {
618 ASC_RESULT_REJECTEDPERMANENT, 661 ASC_RESULT_REJECTEDPERMANENT,
642 if (ASC_countAcceptedPresentationContexts(assoc->params) == 0) 685 if (ASC_countAcceptedPresentationContexts(assoc->params) == 0)
643 LOG(INFO) << " (but no valid presentation contexts)"; 686 LOG(INFO) << " (but no valid presentation contexts)";
644 } 687 }
645 688
646 IApplicationEntityFilter* filter = server.HasApplicationEntityFilter() ? &server.GetApplicationEntityFilter() : NULL; 689 IApplicationEntityFilter* filter = server.HasApplicationEntityFilter() ? &server.GetApplicationEntityFilter() : NULL;
647 return new CommandDispatcher(server, assoc, callingIP, callingTitle, filter); 690 return new CommandDispatcher(server, assoc, callingIP, callingAet, filter);
648 } 691 }
649 692
650 bool CommandDispatcher::Step() 693 bool CommandDispatcher::Step()
651 /* 694 /*
652 * This function receives DIMSE commmands over the network connection 695 * This function receives DIMSE commmands over the network connection