diff --git a/src/main/capnhook/hook/usbhook.c b/src/main/capnhook/hook/usbhook.c index 89ba9c2..a7aa9e0 100644 --- a/src/main/capnhook/hook/usbhook.c +++ b/src/main/capnhook/hook/usbhook.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,7 @@ typedef int (*cnh_usbhook_usb_control_msg_t)(usb_dev_handle* dev, int requesttyp /* ------------------------------------------------------------------------------------------------------------------ */ static void _cnh_usbhook_init(void); +static enum cnh_result _cnh_usbhook_invoke_next_reset_advance(struct cnh_usbhook_irp *irp, bool reset_next_handler_advance); static enum cnh_result _cnh_usbhook_invoke_real(struct cnh_usbhook_irp* irp); static enum cnh_result _cnh_usbhook_invoke_real_init(struct cnh_usbhook_irp* irp); @@ -114,33 +116,12 @@ enum cnh_result cnh_usbhook_push_handler(cnh_usbhook_fn_t fn) enum cnh_result cnh_usbhook_invoke_next(struct cnh_usbhook_irp *irp) { - cnh_usbhook_fn_t handler; - enum cnh_result result; + return _cnh_usbhook_invoke_next_reset_advance(irp, false); +} - assert(irp != NULL); - assert(_cnh_usbhook_initted > 0); - - pthread_mutex_lock(&_cnh_usbhook_lock); - - assert(irp->next_handler <= _cnh_usbhook_nhandlers); - - if (irp->next_handler < _cnh_usbhook_nhandlers) { - handler = _cnh_usbhook_handlers[irp->next_handler]; - irp->next_handler++; - } else { - handler = _cnh_usbhook_invoke_real; - irp->next_handler = (size_t) -1; - } - - pthread_mutex_unlock(&_cnh_usbhook_lock); - - result = handler(irp); - - if (result != CNH_RESULT_SUCCESS) { - irp->next_handler = (size_t) -1; - } - - return result; +enum cnh_result cnh_usbhook_invoke_next_reset_advance(struct cnh_usbhook_irp *irp) +{ + return _cnh_usbhook_invoke_next_reset_advance(irp, true); } /* ------------------------------------------------------------------------------------------------------------------ */ @@ -461,6 +442,44 @@ static void _cnh_usbhook_init(void) atomic_store(&_cnh_usbhook_init_in_progress, 0); } +static enum cnh_result _cnh_usbhook_invoke_next_reset_advance(struct cnh_usbhook_irp *irp, bool reset_next_handler_advance) +{ + cnh_usbhook_fn_t handler; + enum cnh_result result; + size_t cur_next_handler; + + assert(irp != NULL); + assert(_cnh_usbhook_initted > 0); + + cur_next_handler = irp->next_handler; + + pthread_mutex_lock(&_cnh_usbhook_lock); + + assert(irp->next_handler <= _cnh_usbhook_nhandlers); + + if (irp->next_handler < _cnh_usbhook_nhandlers) { + handler = _cnh_usbhook_handlers[irp->next_handler]; + irp->next_handler++; + } else { + handler = _cnh_usbhook_invoke_real; + irp->next_handler = (size_t) -1; + } + + pthread_mutex_unlock(&_cnh_usbhook_lock); + + result = handler(irp); + + if (result != CNH_RESULT_SUCCESS) { + irp->next_handler = (size_t) -1; + } + + if (reset_next_handler_advance) { + irp->next_handler = cur_next_handler; + } + + return result; +} + static enum cnh_result _cnh_usbhook_invoke_real(struct cnh_usbhook_irp* irp) { cnh_usbhook_fn_t handler; diff --git a/src/main/capnhook/hook/usbhook.h b/src/main/capnhook/hook/usbhook.h index 1cd4bf4..94700f4 100644 --- a/src/main/capnhook/hook/usbhook.h +++ b/src/main/capnhook/hook/usbhook.h @@ -67,9 +67,29 @@ enum cnh_result cnh_usbhook_push_handler(cnh_usbhook_fn_t fn); * Call this from your hook handler if you want to pass on execution to further * hooked calls reaching the original function at the end of the hook chain. * + * Note: This will advance the irp state in the handler chain. It is not + * possible to re-use that irp for multiple/different invocations. + * * @param irp I/O request package to dispatch * @return Result of the following function dispatching the request package */ enum cnh_result cnh_usbhook_invoke_next(struct cnh_usbhook_irp *irp); +/** + * Same as cnh_usbhook_invoke_next but allows you to define if the you want + * to reset the next handler of the irp to the initial one once the call + * returns. This still returns the results as expected from the invocation + * chain. + * + * However, the irp state is modified and NOT rolled back. Depending on the + * call, it might contain state change and data to be returned. If you need + * to invoke an irp multiple times, you as the caller need to take care of + * buffering any states and recover it accordingly for successive calls on the + * same irp. + * + * @param irp I/O request package to dispatch + * @return Result of the following function dispatching the request package + */ +enum cnh_result cnh_usbhook_invoke_next_reset_advance(struct cnh_usbhook_irp *irp); + #endif