Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Storage service "promiscuous mode" (accept any SOP class) #505

Closed
Ch00k opened this issue Jun 12, 2020 · 6 comments · Fixed by #645
Closed

Storage service "promiscuous mode" (accept any SOP class) #505

Ch00k opened this issue Jun 12, 2020 · 6 comments · Fixed by #645

Comments

@Ch00k
Copy link

Ch00k commented Jun 12, 2020

I am implementing a catch-all storage service, that will accept associations from all kinds of different PACS'es out there, and store whatever is being sent to it in a C-STORE request. I would like the service to run in "promiscuous mode", i.e. accept any kind of storage SOP class the SCU might request.

The Presentation Contexts documentation reads

While pynetdicom can handle association negotiation containing private abstract syntaxes the implementation of the associated services/semantics is up to the end user.

However, my understanding is that what is meant here is that you still have to define your private SOP classes, and then explicitly add them with AE.add_supported_context. Looking at the code, I don't see an easy was to say "I accept everything" (without monkey-patching pieces of pynetdicom anyway).

A workaround would be to indeed define a list of SOP classes and manually add them, but I would like to avoid a situation where my service rejects an association because an SCU counterpart requested some weird private SOP class, that I did not add.

BTW, Orthanc for example does support this.

@Ch00k Ch00k added the question label Jun 12, 2020
@scaramallion
Copy link
Member

scaramallion commented Jun 12, 2020

It looks like Orthanc just assumes that any privately defined SOP Class belongs to the Storage service...

Hmm, let me think about this for a bit.

@scaramallion
Copy link
Member

scaramallion commented Jun 12, 2020

You could override the negotiate_as_acceptor() import in the acse module so that it accepts any presentation context that's not in the supported contexts lists and adds it to the sop_class module:

from pynetdicom import acse
from pynetdicom.presentation import negotiate_as_acceptor as original
from pynetdicom.sop_class import _STORAGE_CLASSES

# Warning! Pseudo-code!
def my_negotiator(req_cx, acc_cx, roles=None):
    for cx in req_cx:
        # This obviously won't work as-is
        # Or maybe just `if cx.abstract_syntax.is_private:` ?
        if cx.abstract_syntax not in acc_cx:
            # Iterate the key, obviously
            _STORAGE_CLASSES['MyPrivateStorage01'] = cx.abstract_syntax
            # Probably need to change this so it defines the transfer syntaxes you support
            acc_cx.append(cx)

    return original(req_cx, acc_cx, roles)

acse.negotiate_as_acceptor = my_negotiator

I think that should be all you need to do. Monkey-patching it is, unfortunately.

@scaramallion
Copy link
Member

I can certainly see the value to such a thing. I might add an option for it to the next release.

@scaramallion scaramallion added this to the v2.0.0 milestone Jun 12, 2020
@Ch00k
Copy link
Author

Ch00k commented Jun 12, 2020

Thanks so much for such a quick response, and for the example piece of code! One thing I don't understand about your code is why do I need to mutate _STORAGE_CLASSES?

@scaramallion
Copy link
Member

scaramallion commented Jun 12, 2020

When the Association object receives a DIMSE service request it calls uid_to_service_class() which is basically just a lookup function that determines which service class to use based on the contents of a bunch of dicts like _STORAGE_CLASSES. Modifying it with the private UID is the simplest way to add a new SOP Class to the Storage service.

I had originally planned to add simpler ways of registering private SOP Classes but I didn't think there'd be much call for it. This is the first request I've gotten for it.

@Spenhouet
Copy link

Spenhouet commented Dec 19, 2022

@scaramallion We have the same requirement (for a test SCP). It seems that the Verification SOP Class is not accepted when the unrestricted mode is activated. I still needed to set contexts=[build_context(Verification)],. Not sure if that is intended and I did not look further into it. Without this, I got a EVT_REJECTED. Just thought might be worth noting this here for anyone requiring the same functionality.

Edit: Just to mention: With the Verification SOP class set, everything works as expected and we are happy that this unrestricted mode exists and was implemented! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants