Example #1
0
    def test_uid_conformance_true(self):
        """Test UID conformance with ENFORCE_UID_CONFORMANCE = True"""
        _config.ENFORCE_UID_CONFORMANCE = True
        primitive = SCP_SCU_RoleSelectionNegotiation()

        with pytest.raises(ValueError):
            primitive.sop_class_uid = 'abc'
Example #2
0
def build_role(uid, scu_role=False, scp_role=False):
    """Return a SCP/SCU Role Selection Negotiation item.

    Parameters
    ----------
    uid : str or UID or sop_class.SOPClass
        The UID or SOPClass instance to use as the *SOP Class UID* parameter
        value.
    scu_role : bool, optional
        True to propose the SCU role for the *Requestor*, False otherwise
        (default).
    scp_role : bool, optional
        True to propose the SCP role for the *Requestor*, False otherwise
        (default).

    Returns
    -------
    pdu_primitives.SCP_SCU_RoleSelectionNegotiation
        The role selection item.
    """
    from pynetdicom.pdu_primitives import SCP_SCU_RoleSelectionNegotiation

    role = SCP_SCU_RoleSelectionNegotiation()
    role.sop_class_uid = uid
    role.scu_role = scu_role
    role.scp_role = scp_role
    return role
Example #3
0
    def test_uid_conformance_false(self):
        """Test UID conformance with ENFORCE_UID_CONFORMANCE = False"""
        _config.ENFORCE_UID_CONFORMANCE = False
        primitive = SCP_SCU_RoleSelectionNegotiation()

        primitive.sop_class_uid = 'abc'
        assert primitive.sop_class_uid == 'abc'
Example #4
0
def build_role(uid: Union[str, UID],
               scu_role: bool = False,
               scp_role: bool = False) -> "SCP_SCU_RoleSelectionNegotiation":
    """Return a SCP/SCU Role Selection Negotiation item.

    .. versionadded:: 1.2

    Parameters
    ----------
    uid : str or UID or sop_class.SOPClass
        The :class:`~pydicom.uid.UID` or subclass of
        :class:`~pynetdicom.sop_class.SOPClass` instance to use as the *SOP
        Class UID* parameter value.
    scu_role : bool, optional
        ``True`` to propose the SCU role for the *Requestor*, ``False``
        otherwise (default).
    scp_role : bool, optional
        ``True`` to propose the SCP role for the *Requestor*, ``False``
        otherwise (default).

    Returns
    -------
    pdu_primitives.SCP_SCU_RoleSelectionNegotiation
        The role selection item.
    """
    from pynetdicom.pdu_primitives import SCP_SCU_RoleSelectionNegotiation

    role = SCP_SCU_RoleSelectionNegotiation()
    role.sop_class_uid = UID(uid)
    role.scu_role = scu_role
    role.scp_role = scp_role
    return role
Example #5
0
    def test_conversion(self):
        """ Check converting to PDU item works correctly """
        primitive = SCP_SCU_RoleSelectionNegotiation()
        primitive.sop_class_uid = b'1.2.840.10008.5.1.4.1.1.2'
        primitive.scp_role = True
        primitive.scu_role = False
        item = primitive.from_primitive()

        assert item.encode() == (
            b'\x54\x00\x00\x1d\x00\x19\x31\x2e\x32\x2e\x38\x34\x30\x2e\x31\x30'
            b'\x30\x30\x38\x2e\x35\x2e\x31\x2e\x34\x2e\x31\x2e\x31\x2e\x32'
            b'\x00\x01')

        primitive = SCP_SCU_RoleSelectionNegotiation()
        primitive.sop_class_uid = b'1.2.840.10008.5.1.4.1.1.2'
        primitive.scp_role = False
        primitive.scu_role = False
        with pytest.raises(ValueError):
            primitive.from_primitive()
Example #6
0
    def test_assignment_and_exceptions(self):
        """ Check incorrect types/values for properties raise exceptions """
        primitive = SCP_SCU_RoleSelectionNegotiation()

        ## Check assignment
        # SOP Class UID
        reference_uid = UID('1.2.840.10008.5.1.4.1.1.2')

        primitive.sop_class_uid = b'1.2.840.10008.5.1.4.1.1.2'
        assert primitive.sop_class_uid == reference_uid

        primitive.sop_class_uid = '1.2.840.10008.5.1.4.1.1.2'
        assert primitive.sop_class_uid == reference_uid

        primitive.sop_class_uid = UID('1.2.840.10008.5.1.4.1.1.2')
        assert primitive.sop_class_uid == reference_uid

        # SCP Role
        primitive.scp_role = False
        assert primitive.scp_role is False

        # SCU Role
        primitive.scu_role = True
        assert primitive.scu_role is True

        ## Check exceptions
        with pytest.raises(TypeError):
            primitive.sop_class_uid = 10

        with pytest.raises(TypeError):
            primitive.sop_class_uid = 45.2

        with pytest.raises(TypeError):
            primitive.scp_role = 1

        with pytest.raises(TypeError):
            primitive.scp_role = 'abc'

        with pytest.raises(TypeError):
            primitive.scu_role = 1

        with pytest.raises(TypeError):
            primitive.scu_role = 'abc'

        # No value set
        primitive = SCP_SCU_RoleSelectionNegotiation()
        with pytest.raises(ValueError):
            item = primitive.from_primitive()

        primitive.sop_class_uid = b'1.2.840.10008.5.1.4.1.1.2'
        with pytest.raises(ValueError):
            item = primitive.from_primitive()

        primitive.scp_role = False
        with pytest.raises(ValueError):
            item = primitive.from_primitive()

        primitive = SCP_SCU_RoleSelectionNegotiation()
        primitive.sop_class_uid = b'1.2.840.10008.5.1.4.1.1.2'
        primitive.scu_role = True
        item = primitive.from_primitive()
        assert item.scu_role
        assert not item.scp_role

        primitive = SCP_SCU_RoleSelectionNegotiation()
        primitive.scp_role = True
        primitive.scu_role = True
        with pytest.raises(ValueError):
            item = primitive.from_primitive()
Example #7
0
def negotiate_as_acceptor(rq_contexts, ac_contexts, roles=None):
    """Process the Presentation Contexts as an Association acceptor.

    Parameters
    ----------
    rq_contexts : list of PresentationContext
        The Presentation Contexts proposed by the peer. Each item has
        values for Context ID, Abstract Syntax and Transfer Syntax.
    ac_contexts : list of PresentationContext
        The Presentation Contexts supported by the local AE when acting
        as an Association acceptor. Each item has values for Context ID
        Abstract Syntax and Transfer Syntax.
    roles : dict or None
        If the requestor has included one or more SCP/SCU Role Selection
        Negotiation items then this will be a dict of
        {SOP Class UID : (SCU role, SCP role)}, otherwise None (default)

    Returns
    -------
    list of PresentationContext
        The accepted presentation context items, each with a Result value
        a Context ID, an Abstract Syntax and one Transfer Syntax item.
        Items are sorted in increasing Context ID value.
    list of SCP_SCU_RoleSelectionNegotiation
        If `roles` is not None then this is a list of SCP/SCU Role Selection
        Negotiation items that can be sent back to the requestor.
    """
    from pynetdicom.pdu_primitives import SCP_SCU_RoleSelectionNegotiation

    roles = roles or {}
    result_contexts = []
    reply_roles = {}

    # No requestor presentation contexts
    if not rq_contexts:
        return result_contexts, []

    # Acceptor doesn't support any presentation contexts
    if not ac_contexts:
        for rq_context in rq_contexts:
            context = PresentationContext()
            context.context_id = rq_context.context_id
            context.abstract_syntax = rq_context.abstract_syntax
            context.transfer_syntax = [rq_context.transfer_syntax[0]]
            context.result = 0x03
            result_contexts.append(context)
        return result_contexts, []

    # Optimisation notes (for iterating through contexts only, not
    #   including actual context negotiation)
    # - Create dict, use set intersection/difference of dict keys: ~600 us
    # - Create dict, iterate over dict keys: ~400 us
    # - Iterate over lists: ~52000 us

    # Requestor may use the same Abstract Syntax in multiple Presentation
    #   Contexts so we need a more specific key than UID
    requestor_contexts = {(cx.context_id, cx.abstract_syntax): cx
                          for cx in rq_contexts}
    # Acceptor supported SOP Classes must be unique so we can use UID as
    #   the key
    acceptor_contexts = {cx.abstract_syntax: cx for cx in ac_contexts}

    for (cntx_id, ab_syntax) in requestor_contexts:
        # Convenience variable
        rq_context = requestor_contexts[(cntx_id, ab_syntax)]

        # Create a new PresentationContext item that will store the
        #   results of the negotiation
        context = PresentationContext()
        context.context_id = cntx_id
        context.abstract_syntax = ab_syntax
        context._as_scu = False
        context._as_scp = False

        # Check if the acceptor supports the Abstract Syntax
        if ab_syntax in acceptor_contexts:
            # Convenience variables
            ac_context = acceptor_contexts[ab_syntax]
            ac_roles = (ac_context.scu_role, ac_context.scp_role)
            try:
                rq_roles = roles[ab_syntax]
                has_role = True
            except KeyError:
                rq_roles = (None, None)
                has_role = False

            # Abstract syntax supported so check Transfer Syntax
            for tr_syntax in rq_context.transfer_syntax:
                # If transfer syntax supported then (provisionally) accept
                if tr_syntax in ac_context.transfer_syntax:
                    context.transfer_syntax = [tr_syntax]
                    context.result = 0x00
                    result_contexts.append(context)
                    break

            ## SCP/SCU Role Selection Negotiation
            #   Only for (provisionally) accepted contexts
            if context.result == 0x00:
                if None in ac_roles:
                    # Default roles
                    context._as_scu = False
                    context._as_scp = True
                    # If either aq.scu_role or ac.scp_role is None then
                    #   don't send an SCP/SCU negotiation reply
                    has_role = False
                else:
                    # Use a LUT to make changes to outcomes easier
                    #   also its much simpler than coding if/then branches
                    outcome = SCP_SCU_ROLES[rq_roles][ac_roles]
                    context._as_scu = outcome[2]
                    context._as_scp = outcome[3]

                # If can't act as either SCU nor SCP then reject the context
                if context.as_scu is False and context.as_scp is False:
                    # User rejection
                    context.result = 0x01

            # Need to check against None as 0x00 is a possible value
            if context.result is None:
                # Reject context - transfer syntax not supported
                context.result = 0x04
                context.transfer_syntax = [rq_context.transfer_syntax[0]]
                result_contexts.append(context)
            elif context.result == 0x00 and has_role:
                # Create new SCP/SCU Role Selection Negotiation item
                role = SCP_SCU_RoleSelectionNegotiation()
                role.sop_class_uid = context.abstract_syntax

                # Can't return 0x01 if proposed 0x00
                if rq_roles[0] is False:
                    role.scu_role = False
                else:
                    role.scu_role = ac_context.scu_role

                if rq_roles[1] is False:
                    role.scp_role = False
                else:
                    role.scp_role = ac_context.scp_role

                reply_roles[context.abstract_syntax] = role
        else:
            # Reject context - abstract syntax not supported
            context.result = 0x03
            context.transfer_syntax = [rq_context.transfer_syntax[0]]
            result_contexts.append(context)

    # Sort by presentation context ID
    #   This isn't required by the DICOM Standard but its a nice thing to do
    result_contexts = sorted(result_contexts, key=lambda x: x.context_id)

    # Sort role selection by abstract syntax, also not required but nice
    reply_roles = sorted(reply_roles.values(), key=lambda x: x.sop_class_uid)

    return result_contexts, reply_roles
Example #8
0
from pynetdicom.pdu_primitives import SCP_SCU_RoleSelectionNegotiation
from pynetdicom.sop_class import (
    PatientRootQueryRetrieveInformationModelGet,
    CTImageStorage
)

# Initialise the Application Entity
ae = AE()

# Add the requested presentation contexts (QR SCU)
ae.add_requested_context(PatientRootQueryRetrieveInformationModelGet)
# Add the requested presentation context (Storage SCP)
ae.add_requested_context(CTImageStorage)

# Add an SCP/SCU Role Selection Negotiation item for CT Image Storage
role = SCP_SCU_RoleSelectionNegotiation()
role.sop_class_uid = CTImageStorage
# We will be acting as an SCP for CT Image Storage
role.scu_role = False
role.scp_role = True

# Extended negotiation items
ext_neg = [role]

# Create our Identifier (query) dataset
# We need to supply a Unique Key Attribute for each level above the
#   Query/Retrieve level
ds = Dataset()
ds.QueryRetrieveLevel = 'PATIENT'
# Unique key for PATIENT level
ds.PatientID = '1CT1'
Example #9
0
    def add_scp_scu_role(self, primitive):
        """Add SCP/SCU Role Selection to the A-ASSOCIATE primitive."""
        contexts = [
            build_context('1.2.840.10008.1.1'),
            build_context('1.2.840.10008.1.2'),
            build_context('1.2.840.10008.1.3'),
            build_context('1.2.840.10008.1.4'),
        ]

        for ii, cx in enumerate(contexts):
            cx.context_id = ii * 2 + 1

        primitive.presentation_context_definition_list = contexts

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.840.10008.1.2'
        item.scu_role = True
        item.scp_role = False
        primitive.user_information.append(item)

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.840.10008.1.3'
        item.scu_role = False
        item.scp_role = True
        primitive.user_information.append(item)

        item = SCP_SCU_RoleSelectionNegotiation()
        item.sop_class_uid = '1.2.840.10008.1.4'
        item.scu_role = True
        item.scp_role = True
        primitive.user_information.append(item)
Example #10
0
def negotiate_unrestricted(rq_contexts: ListCXType,
                           ac_contexts: ListCXType,
                           roles: RoleType = None) -> CXNegotiationReturn:
    """Process the Presentation Contexts as an Association *Acceptor*
    with an unrestricted storage service.

    ..versionadded:: 2.0

    Parameters
    ----------
    rq_contexts : list of PresentationContext
        The Presentation Contexts proposed by the peer. Each item has
        values for Context ID, Abstract Syntax and Transfer Syntax.
    ac_contexts : list of PresentationContext
        The Presentation Contexts supported by the local AE when acting
        as an Association *Acceptor*. Each item has values for Context ID,
        Abstract Syntax and Transfer Syntax.
    roles : dict or None
        If the *Requestor* has included one or more SCP/SCU Role Selection
        Negotiation items then this will be a :class:`dict` of
        ``{'SOP Class UID' : (SCU role, SCP role)}``, otherwise ``None``
        (default)

    Returns
    -------
    list of PresentationContext
        The accepted presentation context items, each with a Result value
        a Context ID, an Abstract Syntax and one Transfer Syntax item.
        Items are sorted in increasing Context ID value.
    list of SCP_SCU_RoleSelectionNegotiation
        If `roles` is not ``None`` then this is a :class:`list` of SCP/SCU Role
        Selection Negotiation items that can be sent back to the *Requestor*.
    """
    from pynetdicom.pdu_primitives import SCP_SCU_RoleSelectionNegotiation

    roles = roles or {}
    storage_contexts: List[PresentationContext] = []
    non_storage_contexts: List[PresentationContext] = []
    reply_roles: Dict[UID, SCP_SCU_RoleSelectionNegotiation] = {}
    storage_uids = _STORAGE_CLASSES.values()

    # Split out private/unknown/storage cx's from everything else
    for cx in rq_contexts:
        ab_syntax = cast(UID, cx.abstract_syntax)
        if (ab_syntax.is_private or ab_syntax in storage_uids
                or not hasattr(pynetdicom.sop_class, ab_syntax.keyword)):
            storage_contexts.append(cx)
        else:
            non_storage_contexts.append(cx)

    # Negotiate non-storage contexts as normal
    result_cx, result_roles = negotiate_as_acceptor(non_storage_contexts,
                                                    ac_contexts, roles)

    # Accept all storage-like contexts
    for rcx in storage_contexts:
        cx = PresentationContext()
        cx.context_id = rcx.context_id
        cx.abstract_syntax = rcx.abstract_syntax
        cx.transfer_syntax = [rcx.transfer_syntax[0]]
        cx.result = 0x00
        cx._as_scu = True
        cx._as_scp = True

        # Role selection
        if rcx.abstract_syntax in roles:
            role = SCP_SCU_RoleSelectionNegotiation()
            role.sop_class_uid = rcx.abstract_syntax

            rq_roles = roles[rcx.abstract_syntax]
            outcome = SCP_SCU_ROLES[rq_roles][(True, True)]
            cx._as_scu = outcome[2]
            cx._as_scp = outcome[3]

            # Can't return 0x01 if proposed 0x00
            role.scu_role = False if not rq_roles[0] else True
            role.scp_role = False if not rq_roles[1] else True

            reply_roles[cast(UID, cx.abstract_syntax)] = role

        result_cx.append(cx)

    # Not required but a nice thing to do
    result_cx = sorted(result_cx, key=lambda x: cast(int, x.context_id))
    result_roles = sorted(reply_roles.values(),
                          key=lambda x: cast(UID, x.sop_class_uid))

    return result_cx, result_roles
Example #11
0
    def download_series(self,
                        seriesInstanceUID,
                        recieved_callback=None,
                        query_model="P"):

        self.recieved_callback = recieved_callback

        ae = AE()

        # Specify which SOP Classes are supported as an SCU
        for context in QueryRetrievePresentationContexts:
            ae.add_requested_context(context.abstract_syntax,
                                     ImplicitVRLittleEndian)
        for context in StoragePresentationContexts[:115]:
            ae.add_requested_context(context.abstract_syntax,
                                     ImplicitVRLittleEndian)

        # Add SCP/SCU Role Selection Negotiation to the extended negotiation
        # We want to act as a Storage SCP
        ext_neg = []
        for context in StoragePresentationContexts:
            role = SCP_SCU_RoleSelectionNegotiation()
            role.sop_class_uid = context.abstract_syntax
            role.scp_role = True
            role.scu_role = False
            ext_neg.append(role)

        handlers = [(evt.EVT_C_STORE, self.on_c_store)]

        if len(self.ae_title) > 0:
            assoc = ae.associate(
                self.host,
                self.port,
                ae_title=self.ae_title,
                ext_neg=ext_neg,
                evt_handlers=handlers,
            )
        else:
            assoc = ae.associate(self.host,
                                 self.port,
                                 ext_neg=ext_neg,
                                 evt_handlers=handlers)

        if assoc.is_established:
            logger.info("Association accepted by the peer")

            dataset = Dataset()
            dataset.SeriesInstanceUID = seriesInstanceUID
            dataset.QueryRetrieveLevel = "SERIES"

            responses = assoc.send_c_get(dataset, query_model=query_model)

            for (a, b) in responses:
                pass

            # Release the association
            assoc.release()

        logger.info("Finished")

        return self.current_dir
Example #12
0

# Create application entity
# Binding to port 0 lets the OS pick an available port
ae = AE(ae_title=args.calling_aet, port=0)

for context in QueryRetrievePresentationContexts:
    ae.add_requested_context(context.abstract_syntax)
for context in StoragePresentationContexts[:115]:
    ae.add_requested_context(context.abstract_syntax)

# Add SCP/SCU Role Selection Negotiation to the extended negotiation
# We want to act as a Storage SCP
ext_neg = []
for context in StoragePresentationContexts:
    role = SCP_SCU_RoleSelectionNegotiation()
    role.sop_class_uid = context.abstract_syntax
    role.scp_role = True
    role.scu_role = False
    ext_neg.append(role)

# Create query dataset
d = Dataset()
d.PatientName = '*'
d.QueryRetrieveLevel = "PATIENT"

if args.worklist:
    query_model = 'W'
elif args.patient:
    query_model = 'P'
elif args.study: