zmq_proxy_hook(3) ================= NAME ---- zmq_proxy_hook - start built-in 0MQ proxy with an hook to modify the messages between the frontend and the backend SYNOPSIS -------- *int zmq_proxy_hook (const void '*frontend', const void '*backend', const void '*capture', const void '*hook', const void '*control');* DESCRIPTION ----------- The _zmq_proxy_hook()_ function starts the built-in 0MQ proxy in the current application thread, as _zmq_proxy()_ or _zmq_proxy_steerable()_ do. Please, refer to these functions for the general description and usage. We describe here only the additional hook provided by the structure "hook" passed as a fith argument. If the hook structure pointer is not NULL, the proxy supports a hook defined as a structure 'zmq_proxy_hook_t' containing a data pointer to any data type and the address of two functions of type 'zmq_hook_f'. The first function, 'front2back_hook' is to manipulate the message received from the frontend, before it is sent to the backend. The second one, 'back2front_hook' is for the way back. Both functions receive as an argument in addition to a pointer to the message, the pointer to the data passed in the 'zmq_proxy_hook_t' structure. This data makes it possible to manage stateful behaviours in the proxy. They receive also the frame number n_ which is 1 for the first frame, n for the nth one, 0 for the last one. This enable to manage specifically the identity frame when ROUTER | STREAM sockets are concerned. Moreover, to give the hook full capabilities, the three sockets passed as parameters to the proxy are also provided to the hook functions, enabling to consume some frames or to add others: ---- typedef int (*zmq_hook_f)(void *frontend, void *backend, void *capture, zmq_msg_t* msg_, size_t n_, void *data_); typedef struct zmq_proxy_hook_t { void *data; zmq_hook_f front2back_hook; zmq_hook_f back2front_hook; } zmq_proxy_hook_t; ---- If the hook pointer is NULL, zmq_proxy_hook behaves exactly as if zmq_proxy or zmq_proxy_steerable had been called. Refer to linkzmq:zmq_socket[3] for a description of the available socket types. Refer to linkzmq:zmq_proxy[3] for a description of the zmq_proxy. Refer to linkzmq:zmq_proxy_steerable[3] for a description of the zmq_proxy_steerable. EXAMPLE USAGE ------------- Filter ~~~~~~ The most simple use is to simply filter the messages for example against vulgarity. Messages are simply scanned against a dictionnary and target words are replaced. ROUTER | STREAM / ROUTER | STREAM proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The data field enables to multiplex as desired identities in a ROUTER/ROUTER or in a STREAM/STREAM proxy or what ever. Such architecture enables also custom load balancers. Sticky ROUTER / ROUTER proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The data field enables to manage sticky identity pairing in a ROUTER/ROUTER proxy. Security mechanism proxying ~~~~~~~~~~~~~~~~~~~~~~~~~~~ We expect to be able to proxy CURVE with the use of this feature. Tests ~~~~~ In an existing application, just change zmq_proxy or zmq_proxy_steerable for zmq_proxy_hook to test anythink, even "Man in the middle" attacks ws security mechanisms with a STREAM/STREAM proxy. RETURN VALUE ------------ The _zmq_proxy_hook()_ function returns the same values than zmq_proxy or zmq_proxy_steerable in the same conditions of use. EXAMPLE ------- This simple example aims at uppercasing the traffic between the frontend and the backend, and lowercasing it on the way back. .Setup the hook ---- struct stats_t { int qt_upper_case; int qt_lower_case; } stats = {NULL, 0, 0}; int upper_case(void*, void*, void*, zmq_msg_t* msg_, size_t n_, void *stats_) { size_t size = zmq_msg_size(msg_); if (!size || n_ == 1) return 0; // skip identity and 0 frames char* message = (char*) zmq_msg_data(msg_); for (size_t i = 0; i < size; i++) if ('a' <= message[i] && message[i] <= 'z') message[i] += 'A' - 'a'; struct stats_t* stats = (struct stats_t*) stats_; stats->qt_upper_case++; return 0; } int lower_case(void*, void*, void*, zmq_msg_t* msg_, size_t n_, void *stats_) { size_t size = zmq_msg_size(msg_); if (!size || n_ == 1) return 0; // skip identity and 0 frames char* message = (char*) zmq_msg_data(msg_); for (size_t i = 0; i < size; i++) if ('A' <= message[i] && message[i] <= 'Z') message[i] += 'a' - 'A'; struct stats_t* stats = (struct stats_t*) stats_; stats->qt_lower_case++; return 0; } zmq_proxy_hook_t hook = { &stats, // data used by the hook functions, passed as void* data_ upper_case, // hook for messages going from frontend to backend lower_case // hook for messages going from backend to frontend }; ---- .in main: ---- int main (void) { setup_test_environment (); void *context = zmq_ctx_new (); assert (context); // Create frontend, backend and control sockets void *frontend = zmq_socket (context, ZMQ_ROUTER); assert (backend); void *backend = zmq_socket (context, ZMQ_DEALER); assert (frontend); void *control = zmq_socket (context, ZMQ_PUB); assert (control); // Bind sockets to TCP ports assert (zmq_bind (frontend, "tcp://*:5555") == 0); assert (zmq_bind (backend, "tcp://*:5556") == 0); assert (zmq_connect (control, "tcp://*:5557") == 0); // Start the queue proxy, which runs until ETERM or "TERMINATE" // received on the control socket zmq_proxy_hook (frontend, backend, NULL, &hook, control); printf("frontend to backend hook hits = %d\nbackend to frontend hook hits = %d\n", stats.qt_upper_case, stats.qt_lower_case); // close sockets and context rc = zmq_close (control); assert (rc == 0); rc = zmq_close (backend); assert (rc == 0); rc = zmq_close (frontend); assert (rc == 0); rc = zmq_ctx_term (ctx); assert (rc == 0); return 0; } ---- .somewhere, the proxy is stopped with: ---- rc = zmq_send (control, "TERMINATE", 9, 0); // stops the hooked proxy assert (rc == 9); ---- .cf test_proxy.cpp for a full implementation of this test, with clients and workers. SEE ALSO -------- linkzmq:zmq_proxy[3] linkzmq:zmq_proxy_steerable[3] linkzmq:zmq_bind[3] linkzmq:zmq_connect[3] linkzmq:zmq_socket[3] linkzmq:zmq[7] AUTHORS ------- This page was written by the 0MQ community. To make a change please read the 0MQ Contribution Policy at .