Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Socketevent bitflags macro #353

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 36 additions & 54 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,56 +95,39 @@ impl SocketType {
}
}

/// Socket Events
#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SocketEvent {
// TODO: This should become a proper enum, including the data.
CONNECTED = zmq_sys::ZMQ_EVENT_CONNECTED as isize,
CONNECT_DELAYED = zmq_sys::ZMQ_EVENT_CONNECT_DELAYED as isize,
CONNECT_RETRIED = zmq_sys::ZMQ_EVENT_CONNECT_RETRIED as isize,
LISTENING = zmq_sys::ZMQ_EVENT_LISTENING as isize,
BIND_FAILED = zmq_sys::ZMQ_EVENT_BIND_FAILED as isize,
ACCEPTED = zmq_sys::ZMQ_EVENT_ACCEPTED as isize,
ACCEPT_FAILED = zmq_sys::ZMQ_EVENT_ACCEPT_FAILED as isize,
CLOSED = zmq_sys::ZMQ_EVENT_CLOSED as isize,
CLOSE_FAILED = zmq_sys::ZMQ_EVENT_CLOSE_FAILED as isize,
DISCONNECTED = zmq_sys::ZMQ_EVENT_DISCONNECTED as isize,
MONITOR_STOPPED = zmq_sys::ZMQ_EVENT_MONITOR_STOPPED as isize,
HANDSHAKE_FAILED_NO_DETAIL = zmq_sys::ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL as isize,
HANDSHAKE_SUCCEEDED = zmq_sys::ZMQ_EVENT_HANDSHAKE_SUCCEEDED as isize,
HANDSHAKE_FAILED_PROTOCOL = zmq_sys::ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL as isize,
HANDSHAKE_FAILED_AUTH = zmq_sys::ZMQ_EVENT_HANDSHAKE_FAILED_AUTH as isize,
ALL = zmq_sys::ZMQ_EVENT_ALL as isize,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed prior, all() returns a union of all flags, which for this pair of constants seems to result in (1<<15) - 1 whereas ZMQ_EVENT_ALL is defined as (1 << 16) - 1 - the highest bit 1<<15 isn't used by a constant yet.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the suggestion is to probably keep this around - which automatically makes ::all() return the same value as ALL even if there's one bit that appears to be "reserved".

}

impl SocketEvent {
pub fn to_raw(self) -> u16 {
self as u16
}

// TODO: this should not need to be public
pub fn from_raw(raw: u16) -> SocketEvent {
use SocketEvent::*;
match u32::from(raw) {
zmq_sys::ZMQ_EVENT_CONNECTED => CONNECTED,
zmq_sys::ZMQ_EVENT_CONNECT_DELAYED => CONNECT_DELAYED,
zmq_sys::ZMQ_EVENT_CONNECT_RETRIED => CONNECT_RETRIED,
zmq_sys::ZMQ_EVENT_LISTENING => LISTENING,
zmq_sys::ZMQ_EVENT_BIND_FAILED => BIND_FAILED,
zmq_sys::ZMQ_EVENT_ACCEPTED => ACCEPTED,
zmq_sys::ZMQ_EVENT_ACCEPT_FAILED => ACCEPT_FAILED,
zmq_sys::ZMQ_EVENT_CLOSED => CLOSED,
zmq_sys::ZMQ_EVENT_CLOSE_FAILED => CLOSE_FAILED,
zmq_sys::ZMQ_EVENT_DISCONNECTED => DISCONNECTED,
zmq_sys::ZMQ_EVENT_MONITOR_STOPPED => MONITOR_STOPPED,
zmq_sys::ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL => HANDSHAKE_FAILED_NO_DETAIL,
zmq_sys::ZMQ_EVENT_HANDSHAKE_SUCCEEDED => HANDSHAKE_SUCCEEDED,
zmq_sys::ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL => HANDSHAKE_FAILED_PROTOCOL,
zmq_sys::ZMQ_EVENT_HANDSHAKE_FAILED_AUTH => HANDSHAKE_FAILED_AUTH,
zmq_sys::ZMQ_EVENT_ALL => ALL,
x => panic!("unknown event type {}", x),
}
bitflags! {
/// A bitmask of the socket events you wish to monitor
pub struct SocketEvent: u32 {
/// The socket has successfully connected to a remote peer. The event value is the file descriptor (FD) of the underlying network socket. Warning: there is no guarantee that the FD is still valid by the time your code receives this event.
const CONNECTED = zmq_sys::ZMQ_EVENT_CONNECTED;
/// A connect request on the socket is pending. The event value is unspecified.
const CONNECT_DELAYED = zmq_sys::ZMQ_EVENT_CONNECT_DELAYED;
/// A connect request failed, and is now being retried. The event value is the reconnect interval in milliseconds. Note that the reconnect interval is recalculated at each retry.
const CONNECT_RETRIED = zmq_sys::ZMQ_EVENT_CONNECT_RETRIED;
/// The socket was successfully bound to a network interface. The event value is the FD of the underlying network socket. Warning: there is no guarantee that the FD is still valid by the time your code receives this event.
const LISTENING = zmq_sys::ZMQ_EVENT_LISTENING;
/// The socket could not bind to a given interface. The event value is the errno generated by the system bind call.
const BIND_FAILED = zmq_sys::ZMQ_EVENT_BIND_FAILED;
/// The socket has accepted a connection from a remote peer. The event value is the FD of the underlying network socket. Warning: there is no guarantee that the FD is still valid by the time your code receives this event.
const ACCEPTED = zmq_sys::ZMQ_EVENT_ACCEPTED;
/// The socket has rejected a connection from a remote peer. The event value is the errno generated by the accept call.
const ACCEPT_FAILED = zmq_sys::ZMQ_EVENT_ACCEPT_FAILED;
/// The socket was closed. The event value is the FD of the (now closed) network socket.
const CLOSED = zmq_sys::ZMQ_EVENT_CLOSED;
/// The socket close failed. The event value is the errno returned by the system call. Note that this event occurs only on IPC transports.
const CLOSE_FAILED = zmq_sys::ZMQ_EVENT_CLOSE_FAILED;
/// The socket was disconnected unexpectedly. The event value is the FD of the underlying network socket. Warning: this socket will be closed.
const DISCONNECTED = zmq_sys::ZMQ_EVENT_DISCONNECTED;
/// Monitoring on this socket ended.
const MONITOR_STOPPED = zmq_sys::ZMQ_EVENT_MONITOR_STOPPED;
/// Unspecified system errors during handshake.
const HANDSHAKE_FAILED_NO_DETAIL = zmq_sys::ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL;
/// Handshake complete successfully with successful authentication (if enabled).
const HANDSHAKE_SUCCEEDED = zmq_sys::ZMQ_EVENT_HANDSHAKE_SUCCEEDED;
/// Protocol errors between ZMTP peers or between server and ZAP handler.
const HANDSHAKE_FAILED_PROTOCOL = zmq_sys::ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL;
/// Failed authentication requests. Event value is the numeric ZAP status code, i.e. 300, 400 or 500.
const HANDSHAKE_FAILED_AUTH = zmq_sys::ZMQ_EVENT_HANDSHAKE_FAILED_AUTH;
}
}

Expand Down Expand Up @@ -669,11 +652,10 @@ impl Socket {
}

/// Configure the socket for monitoring
pub fn monitor(&self, monitor_endpoint: &str, events: i32) -> Result<()> {
pub fn monitor(&self, monitor_endpoint: &str, events: SocketEvent) -> Result<()> {
let c_str = ffi::CString::new(monitor_endpoint.as_bytes()).unwrap();
zmq_try!(unsafe {
zmq_sys::zmq_socket_monitor(self.sock, c_str.as_ptr(), events as c_int)
});
let c_int = ffi::c_int::from(events.bits as i32);
zmq_try!(unsafe { zmq_sys::zmq_socket_monitor(self.sock, c_str.as_ptr(), c_int) });
Ok(())
}

Expand Down
9 changes: 5 additions & 4 deletions tests/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ fn get_monitor_event(monitor: &mut zmq::Socket) -> zmq::Result<zmq::SocketEvent>
let msg = monitor.recv_msg(0)?;
// TODO: could be simplified by using `TryInto` (since 1.34)
let event = u16::from_ne_bytes([msg[0], msg[1]]);
let event = zmq::SocketEvent::from_bits(event as u32).unwrap();

assert!(
monitor.get_rcvmore()?,
Expand All @@ -23,7 +24,7 @@ fn get_monitor_event(monitor: &mut zmq::Socket) -> zmq::Result<zmq::SocketEvent>
// the address, we'll ignore it
let _ = monitor.recv_msg(0)?;

Ok(zmq::SocketEvent::from_raw(event))
Ok(event)
}

fn expect_event(mon: &mut zmq::Socket, expected: zmq::SocketEvent) {
Expand Down Expand Up @@ -77,15 +78,15 @@ test!(test_monitor_events, {
let mut server = ctx.socket(zmq::DEALER).unwrap();

let err = client
.monitor("tcp://127.0.0.1:9999", 0)
.monitor("tcp://127.0.0.1:9999", zmq::SocketEvent::empty())
.expect_err("Socket monitoring only works over inproc://");
assert_eq!(zmq::Error::EPROTONOSUPPORT, err);

assert!(client
.monitor("inproc://monitor-client", zmq::SocketEvent::ALL as i32)
.monitor("inproc://monitor-client", zmq::SocketEvent::all())
.is_ok());
assert!(server
.monitor("inproc://monitor-server", zmq::SocketEvent::ALL as i32)
.monitor("inproc://monitor-server", zmq::SocketEvent::all())
.is_ok());

let mut client_mon = ctx.socket(zmq::PAIR).unwrap();
Expand Down