![]() |
Mads
Multi-Agent Distributed System
|
One monitor per monitored socket. start() must be called before the socket's connect()/bind(): libzmq lets a connection through – and may fire its lifecycle events – while no monitor is attached yet, exactly the same race Mads::ZapAuth::start() avoids for the ZAP handler. More...
#include <socket_monitor.hpp>
Public Member Functions | |
| SocketMonitor () | |
| ~SocketMonitor () | |
| SocketMonitor (const SocketMonitor &)=delete | |
| SocketMonitor & | operator= (const SocketMonitor &)=delete |
| void | start (zmq::socket_t &socket, int events=ZMQ_EVENT_ALL) |
Starts monitoring socket on a private inproc:// endpoint and a dedicated thread. A second call before stop() is a no-op. | |
| void | attach (zmq::socket_t &socket, int events=ZMQ_EVENT_ALL) |
Attaches to socket without starting any thread, leaving the caller to drive the monitor: include pollable() in a zmq::poll() and call process_pending() whenever it reports ZMQ_POLLIN. | |
| zmq::socket_ref | pollable () const |
The monitor's own PAIR socket, for inclusion in the caller's zmq::poll(). Its handle() is null until attach()/start() has run, and null again after stop() – so a driving loop can simply re-read it every iteration and pick up a monitor that was attached later. | |
| void | process_pending () |
| Consumes the events pollable() has signalled, updating last_event()/state() and waking the wait_*() calls. | |
| void | stop () |
Stops the monitoring thread (if start() created one) and detaches from the socket (zmq_socket_monitor(socket, nullptr, 0)). Must be called – directly or via the destructor – before the monitored socket is closed. Safe to call more than once and safe if neither start() nor attach() was ever called. | |
| bool | wait_connected (std::chrono::milliseconds timeout) |
Blocks until a Connected or HandshakeSucceeded event is observed, or timeout elapses. This is a fast "did the transport come up" signal only – ZMQ_EVENT_CONNECTED fires at the TCP level, before any ZMTP security mechanism (NULL/PLAIN/CURVE) has been negotiated. Callers that need to know the handshake itself succeeded (e.g. distinguishing a CURVE rejection from an ordinary connect) must use wait_handshake_succeeded() instead. | |
| bool | wait_handshake_succeeded (std::chrono::milliseconds timeout) |
Blocks until a ZMTP handshake completes one way or the other, or timeout elapses. Unlike wait_connected(), this does not accept a bare Connected event, so it is not fooled by a CURVE/ZAP rejection: TCP connects immediately regardless of the mechanism, but the handshake only succeeds once the security layer has actually accepted the peer. | |
| LinkEvent | last_event () const |
| The most recent event observed (None if none yet). | |
| LinkState | state () const |
| A consistent snapshot of the link's current status, the event that produced it, and how often it has dropped and recovered. | |
| std::string | last_event_address () const |
One monitor per monitored socket. start() must be called before the socket's connect()/bind(): libzmq lets a connection through – and may fire its lifecycle events – while no monitor is attached yet, exactly the same race Mads::ZapAuth::start() avoids for the ZAP handler.
The monitor runs its own background thread polling the inproc:// pair zmq_socket_monitor() publishes to; nothing about it touches the monitored socket itself, so it composes with any other use of that socket.
state() assumes the monitored socket connects to a single peer. A bound socket gets ZMQ_EVENT_ACCEPTED (not CONNECTED/HANDSHAKE_SUCCEEDED) per arriving peer and ZMQ_EVENT_DISCONNECTED per departing one, so its events would add up to "down" the moment any one of several peers left; use last_event() there, or nothing at all.
Definition at line 114 of file socket_monitor.hpp.
| Mads::SocketMonitor::SocketMonitor | ( | ) |
| Mads::SocketMonitor::~SocketMonitor | ( | ) |
|
delete |
| void Mads::SocketMonitor::attach | ( | zmq::socket_t & | socket, |
| int | events = ZMQ_EVENT_ALL |
||
| ) |
Attaches to socket without starting any thread, leaving the caller to drive the monitor: include pollable() in a zmq::poll() and call process_pending() whenever it reports ZMQ_POLLIN.
This is what lets several monitors – or a monitor and the application's own sockets – share one poll loop instead of one thread each (ZMQ_DEVELOPMENT.md ยง4.1). Same ordering contract as start(): call it before the socket's connect()/bind().
A second call before stop() is a no-op, so a caller that reconnects can call it again without re-arming zmq_socket_monitor().
| LinkEvent Mads::SocketMonitor::last_event | ( | ) | const |
The most recent event observed (None if none yet).
| std::string Mads::SocketMonitor::last_event_address | ( | ) | const |
The libzmq-reported peer address the most recent event carried (empty if none yet).
|
delete |
| zmq::socket_ref Mads::SocketMonitor::pollable | ( | ) | const |
| void Mads::SocketMonitor::process_pending | ( | ) |
Consumes the events pollable() has signalled, updating last_event()/state() and waking the wait_*() calls.
Call only from the thread that polls pollable(), and only when that poll reported ZMQ_POLLIN – like the socket it drains, this is not thread-safe. A monitor driven this way must not be stop()ped until that thread has been joined.
| void Mads::SocketMonitor::start | ( | zmq::socket_t & | socket, |
| int | events = ZMQ_EVENT_ALL |
||
| ) |
| LinkState Mads::SocketMonitor::state | ( | ) | const |
A consistent snapshot of the link's current status, the event that produced it, and how often it has dropped and recovered.
Only ZMQ_EVENT_HANDSHAKE_SUCCEEDED raises the status to Up. A bare ZMQ_EVENT_CONNECTED deliberately does not: it fires as soon as TCP is established, before the ZMTP security mechanism has run, so a CURVE rejection would otherwise register as a connection immediately followed by a spurious drop.
| void Mads::SocketMonitor::stop | ( | ) |
Stops the monitoring thread (if start() created one) and detaches from the socket (zmq_socket_monitor(socket, nullptr, 0)). Must be called – directly or via the destructor – before the monitored socket is closed. Safe to call more than once and safe if neither start() nor attach() was ever called.
This resets what state() reports back to Unknown with zeroed counters: a detached monitor has no link to describe, and a later start() begins a fresh observation rather than resuming a stale one.
| bool Mads::SocketMonitor::wait_connected | ( | std::chrono::milliseconds | timeout | ) |
Blocks until a Connected or HandshakeSucceeded event is observed, or timeout elapses. This is a fast "did the transport come up" signal only – ZMQ_EVENT_CONNECTED fires at the TCP level, before any ZMTP security mechanism (NULL/PLAIN/CURVE) has been negotiated. Callers that need to know the handshake itself succeeded (e.g. distinguishing a CURVE rejection from an ordinary connect) must use wait_handshake_succeeded() instead.
| bool Mads::SocketMonitor::wait_handshake_succeeded | ( | std::chrono::milliseconds | timeout | ) |
Blocks until a ZMTP handshake completes one way or the other, or timeout elapses. Unlike wait_connected(), this does not accept a bare Connected event, so it is not fooled by a CURVE/ZAP rejection: TCP connects immediately regardless of the mechanism, but the handshake only succeeds once the security layer has actually accepted the peer.
Decided on state().last_handshake rather than the newest event, so the DISCONNECTED that libzmq fires straight after a rejection cannot make this report a timeout instead of a refusal.