mirror of
https://github.com/zeromq/libzmq.git
synced 2024-12-13 10:52:56 +01:00
202 lines
6.3 KiB
Plaintext
202 lines
6.3 KiB
Plaintext
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 statefull 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 <http://www.zeromq.org/docs:contributing>.
|