python-pkcs11 icon indicating copy to clipboard operation
python-pkcs11 copied to clipboard

"FIXME: cancel the operation when we exit the generator early."

Open figbux opened this issue 5 years ago • 3 comments

Hello,

I'm facing this not-fixed issue due to cancelling an operation in the middle. In my specific case, I have to cancel before finishing; so I have to overcome this issue.

For encryption, I overcame this by adding an _encrypt_halt() method, which used to work fine:

     # call this in OperationActive exception
     def _encrypt_halt(self):
        cdef CK_BYTE [:] tmp_out = CK_BYTE_buffer(8192)
        cdef CK_ULONG tmp_len = 8192
        # try to consume the buffer
        assertRV(_funclist.C_EncryptFinal(self.session._handle,
                                &tmp_out[0], &tmp_len))

But I think this is a hack, not the proper way. Doing similar for sign/verify functions etc. not working; so I've decided to really fix the issue.

What is the best way of cancelling an operation? Hopefully I'll implement it.

figbux avatar Mar 11 '20 09:03 figbux

There's two ways I can see to do this. One- wrap your input generator, to have a cancellation function, that if set raises StopIteration. This should cause our consumption of the generator to shut down.

Something like this:

class CancellableIter:
    def __init__(self, iter_):
        self.cancelled = False
        self._iter = iter(iter_)

    def cancel(self):
        self.cancelled = True

    def __iter__(self):
        return self

    def __next__(self):
        if self.cancelled: raise StopIteration()
        return next(self._iter)

iter_ = CancellableIter(data)
for chunk in session.encrypt(iter_):
    iter_.cancel()
    continue  # Not break, else it won't execute another pass of the iterator.

I haven't tested this, but something like it should work in theory.

Otherwise have a look at how SearchIter functions. Fundamentally it's an iterator object that let's you consume the data but also has a __del__ function to handle the cancel. The reason I've never done this is because I couldn't work out how to build it generically without needing a class for every generator.

danni avatar Mar 15 '20 23:03 danni

Sorry for lateness,

I tried this. Then I figured out that actually I never trigger a chunked operation. I call encrypt with single data, not an iterable. And I can trigger OperationActive in non-chunked operations.

For chunked ones, I can use your suggestion, for non-chunked, what could be done?

figbux avatar Mar 26 '20 10:03 figbux

So that’s interesting and unexpected. Do you have multiple threads? There’s a section in the docs on concurrency issues. You might have to add some debugging to work out what’s going on there, because there should be locking that protects you from any kind of concurrency issue in operations. On 26 Mar 2020, 21:34 +1100, figbux [email protected], wrote:

Sorry for lateness, I tried this. Then I figured out that actually I never trigger a chunked operation. I call encrypt with single data, not an iterable. And I can trigger OperationActive in non-chunked operations. For chunked ones, I can use your suggestion, for non-chunked, what could be done? — You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

danni avatar Mar 26 '20 11:03 danni