1
0
mirror of https://github.com/pumpitupdev/pumptools.git synced 2024-11-28 00:20:47 +01:00

capnhook/usbhook: Add invoce next function that resets next handlers

Required for piuio-khack which needs to convert a single libusb
call into 8 separate calls. In that case, we want to advance the
handlers downstream but reset it once we go back up to the invocation
which needs to scatter to multiple calls. As stated by the documentation,
state handling of the irp is not taken care of. This is fine, since
at this point, we don't know what the function is and the caller needs
to take care of regarding saving and recovering any state in the irp.
This commit is contained in:
icex2 2021-03-19 12:31:26 +01:00
parent 5a2c8b5104
commit 0a01503227
2 changed files with 65 additions and 26 deletions

View File

@ -4,6 +4,7 @@
#include <errno.h>
#include <pthread.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <string.h>
#include <usb.h>
@ -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;
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;
return _cnh_usbhook_invoke_next_reset_advance(irp, false);
}
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;

View File

@ -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