org.zeromq.ZMQ Maven / Gradle / Ivy
/*
Copyright (c) 2007-2010 iMatix Corporation
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the Lesser GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Lesser GNU General Public License for more details.
You should have received a copy of the Lesser GNU General Public License
along with this program. If not, see .
*/
package org.zeromq;
import java.io.Closeable;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.channels.SelectableChannel;
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* ZeroMQ JNI Bindings.
*
* @author Gonzalo Diethelm
*
*/
public class ZMQ {
static {
// if no embedded native library, revert to loading from java.library.path
if (!EmbeddedLibraryTools.LOADED_EMBEDDED_LIBRARY)
System.loadLibrary("jzmq");
}
// Values for flags in Socket's send and recv functions.
/**
* Socket flag to indicate a nonblocking send or recv mode.
*/
public static final int NOBLOCK = 1;
public static final int DONTWAIT = 1;
/**
* Socket flag to indicate that more message parts are coming.
*/
public static final int SNDMORE = 2;
// Socket types, used when creating a Socket.
/**
* Flag to specify a exclusive pair of items.
*/
public static final int PAIR = 0;
/**
* Flag to specify a PUB socket, receiving side must be a SUB or XSUB.
*/
public static final int PUB = 1;
/**
* Flag to specify the receiving part of the PUB or XPUB socket.
*/
public static final int SUB = 2;
/**
* Flag to specify a REQ socket, receiving side must be a REP.
*/
public static final int REQ = 3;
/**
* Flag to specify the receiving part of a REQ socket.
*/
public static final int REP = 4;
/**
* Flag to specify a DEALER socket (aka XREQ). DEALER is really a combined ventilator / sink that does
* load-balancing on output and fair-queuing on input with no other semantics. It is the only socket type that lets
* you shuffle messages out to N nodes and shuffle the replies back, in a raw bidirectional asynch pattern.
*/
public static final int DEALER = 5;
/**
* Old alias for DEALER flag. Flag to specify a XREQ socket, receiving side must be a XREP.
*
* @deprecated As of release 3.0 of zeromq, replaced by {@link #DEALER}
*/
public static final int XREQ = DEALER;
/**
* Flag to specify ROUTER socket (aka XREP). ROUTER is the socket that creates and consumes request-reply routing
* envelopes. It is the only socket type that lets you route messages to specific connections if you know their
* identities.
*/
public static final int ROUTER = 6;
/**
* Old alias for ROUTER flag. Flag to specify the receiving part of a XREQ socket.
*
* @deprecated As of release 3.0 of zeromq, replaced by {@link #ROUTER}
*/
public static final int XREP = ROUTER;
/**
* Flag to specify the receiving part of a PUSH socket.
*/
public static final int PULL = 7;
/**
* Flag to specify a PUSH socket, receiving side must be a PULL.
*/
public static final int PUSH = 8;
/**
* Flag to specify a XPUB socket, receiving side must be a SUB or XSUB. Subscriptions can be received as a message.
* Subscriptions start with a '1' byte. Unsubscriptions start with a '0' byte.
*/
public static final int XPUB = 9;
/**
* Flag to specify the receiving part of the PUB or XPUB socket. Allows
*/
public static final int XSUB = 10;
/**
* Flag to specify a STREAMER device.
*/
public static final int STREAMER = 1;
/**
* Flag to specify a FORWARDER device.
*/
public static final int FORWARDER = 2;
/**
* Flag to specify a QUEUE device.
*/
public static final int QUEUE = 3;
/**
* @see ZMQ#PULL
*/
@Deprecated
public static final int UPSTREAM = PULL;
/**
* @see ZMQ#PUSH
*/
@Deprecated
public static final int DOWNSTREAM = PUSH;
/**
* EVENT_CONNECTED: connection established.
* The EVENT_CONNECTED event triggers when a connection has been
* established to a remote peer. This can happen either synchronous
* or asynchronous. Value is the FD of the newly connected socket.
*/
public static final int EVENT_CONNECTED = 1;
/**
* EVENT_CONNECT_DELAYED: synchronous connect failed, it's being polled.
* The EVENT_CONNECT_DELAYED event triggers when an immediate connection
* attempt is delayed and its completion is being polled for. Value has
* no meaning.
*/
public static final int EVENT_CONNECT_DELAYED = 2;
/**
* EVENT_CONNECT_RETRIED: asynchronous connect / reconnection attempt.
* The EVENT_CONNECT_RETRIED event triggers when a connection attempt is
* being handled by reconnect timer. The reconnect interval's recomputed
* for each attempt. Value is the reconnect interval.
*/
public static final int EVENT_CONNECT_RETRIED = 4;
/**
* EVENT_LISTENING: socket bound to an address, ready to accept connections.
* The EVENT_LISTENING event triggers when a socket's successfully bound to
* a an interface. Value is the FD of the newly bound socket.
*/
public static final int EVENT_LISTENING = 8;
/**
* EVENT_BIND_FAILED: socket could not bind to an address.
* The EVENT_BIND_FAILED event triggers when a socket could not bind to a
* given interface. Value is the errno generated by the bind call.
*/
public static final int EVENT_BIND_FAILED = 16;
/**
* EVENT_ACCEPTED: connection accepted to bound interface.
* The EVENT_ACCEPTED event triggers when a connection from a remote peer
* has been established with a socket's listen address. Value is the FD of
* the accepted socket.
*/
public static final int EVENT_ACCEPTED = 32;
/**
* EVENT_ACCEPT_FAILED: could not accept client connection.
* The EVENT_ACCEPT_FAILED event triggers when a connection attempt to a
* socket's bound address fails. Value is the errno generated by accept.
*/
public static final int EVENT_ACCEPT_FAILED = 64;
/**
* EVENT_CLOSED: connection closed.
* The EVENT_CLOSED event triggers when a connection's underlying
* descriptor has been closed. Value is the former FD of the for the
* closed socket. FD has been closed already!
*/
public static final int EVENT_CLOSED = 128;
/**
* EVENT_CLOSE_FAILED: connection couldn't be closed.
* The EVENT_CLOSE_FAILED event triggers when a descriptor could not be
* released back to the OS. Implementation note: ONLY FOR IPC SOCKETS.
* Value is the errno generated by unlink.
*/
public static final int EVENT_CLOSE_FAILED = 256;
/**
* EVENT_DISCONNECTED: broken session.
* The EVENT_DISCONNECTED event triggers when the stream engine (tcp and
* ipc specific) detects a corrupted / broken session. Value is the FD of
* the socket.
*/
public static final int EVENT_DISCONNECTED = 512;
/**
* EVENT_MONITOR_STOPPED: monitor has been stopped.
* The EVENT_MONITOR_STOPPED event triggers when the monitor for a socket is
* stopped.
*/
public static final int EVENT_MONITOR_STOPPED = 1024;
/**
* EVENT_ALL: all events known by the java binding.
* The EVENT_ALL constant can be used to set up a monitor for all events known
* by the java binding. One could add more flags
*/
public static final int EVENT_ALL = EVENT_CONNECTED | EVENT_CONNECT_DELAYED | EVENT_CONNECT_RETRIED |
EVENT_LISTENING | EVENT_BIND_FAILED | EVENT_ACCEPTED | EVENT_ACCEPT_FAILED |
EVENT_CLOSED | EVENT_CLOSE_FAILED | EVENT_DISCONNECTED | EVENT_MONITOR_STOPPED;
/**
* @return Major version number of the ZMQ library.
*/
public static int getMajorVersion() {
return version_major();
}
/**
* @return Major version number of the ZMQ library.
*/
public static int getMinorVersion() {
return version_minor();
}
/**
* @return Major version number of the ZMQ library.
*/
public static int getPatchVersion() {
return version_patch();
}
/**
* @return Full version number of the ZMQ library used for comparing versions.
*/
public static int getFullVersion() {
return version_full();
}
/**
* @param major Version major component.
* @param minor Version minor component.
* @param patch Version patch component.
*
* @return Comparible single int version number.
*/
public static int makeVersion(final int major, final int minor, final int patch) {
return make_version(major, minor, patch);
}
/**
* @return String version number in the form major.minor.patch.
*/
public static String getVersionString() {
return String.format("%d.%d.%d", version_major(), version_minor(), version_patch());
}
/**
* Starts the built-in 0MQ proxy in the current application thread. The proxy connects a frontend socket to a
* backend socket. Conceptually, data flows from frontend to backend. Depending on the socket types, replies may
* flow in the opposite direction. The direction is conceptual only; the proxy is fully symmetric and there is no
* technical difference between frontend and backend.
*
* Before calling ZMQ.proxy() you must set any socket options, and connect or bind both frontend and backend
* sockets. The two conventional proxy models are:
*
* ZMQ.proxy() runs in the current thread and returns only if/when the current context is closed.
*
* @param frontend ZMQ.Socket
* @param backend ZMQ.Socket
* @param capture If the capture socket is not NULL, the proxy shall send all messages, received on both frontend
* and backend, to the capture socket. The capture socket should be a ZMQ_PUB, ZMQ_DEALER, ZMQ_PUSH, or
* ZMQ_PAIR socket.
* @since 3.2.2
*/
public static void proxy(Socket frontend, Socket backend, Socket capture) {
if (ZMQ.version_full() < ZMQ.make_version(3, 2, 2))
throw new UnsupportedOperationException();
run_proxy(frontend, backend, capture);
}
/**
* Poll on polling items until timeout
*
* @param items polling items
* @param timeout timeout in millisecond
* @return number of events
*/
public static int poll(PollItem[] items, long timeout) {
return poll(items, items.length, timeout);
}
/**
* Poll on polling items until timeout
*
* @param items polling items
* @param count active item count
* @param timeout timeout in millisecond
* @return number of events
*/
public static int poll(PollItem[] items, int count, long timeout) {
return Poller.run_poll(items, count, timeout);
}
protected static native int version_full();
protected static native int version_major();
protected static native int version_minor();
protected static native int version_patch();
protected static native int make_version(int major, int minor, int patch);
protected static native long ENOTSUP();
protected static native long EPROTONOSUPPORT();
protected static native long ENOBUFS();
protected static native long ENETDOWN();
protected static native long EADDRINUSE();
protected static native long EADDRNOTAVAIL();
protected static native long ECONNREFUSED();
protected static native long EINPROGRESS();
protected static native long EHOSTUNREACH();
protected static native long EMTHREAD();
protected static native long EFSM();
protected static native long ENOCOMPATPROTO();
protected static native long ETERM();
protected static native long ENOTSOCK();
private static native void run_proxy(Socket frontend, Socket backend, Socket capture);
/**
* Inner class: Error.
*/
public enum Error {
ENOTSUP(ENOTSUP()),
EPROTONOSUPPORT(EPROTONOSUPPORT()),
ENOBUFS(ENOBUFS()),
ENETDOWN(ENETDOWN()),
EADDRINUSE(EADDRINUSE()),
EADDRNOTAVAIL(EADDRNOTAVAIL()),
ECONNREFUSED(ECONNREFUSED()),
EINPROGRESS(EINPROGRESS()),
EHOSTUNREACH(EHOSTUNREACH()),
EMTHREAD(EMTHREAD()),
EFSM(EFSM()),
ENOCOMPATPROTO(ENOCOMPATPROTO()),
ETERM(ETERM()),
ENOTSOCK(ENOTSOCK());
private final long code;
Error(long code) {
this.code = code;
}
public long getCode() {
return code;
}
public static Error findByCode(int code) {
for (Error e : Error.class.getEnumConstants()) {
if (e.getCode() == code) {
return e;
}
}
throw new IllegalArgumentException("Unknown " + Error.class.getName() + " enum code:" + code);
}
}
/**
* Create a new Context.
*
* @param ioThreads Number of threads to use, usually 1 is sufficient for most use cases.
* @return the Context
*/
public static Context context(int ioThreads) {
return new Context(ioThreads);
}
/**
* Inner class: Context.
*/
public static class Context implements Closeable {
private final AtomicBoolean closed = new AtomicBoolean(false);
/**
* This is an explicit "destructor". It can be called to ensure the corresponding 0MQ Context has been disposed
* of.
*/
public void term() {
if(closed.compareAndSet(false, true)) {
destroy();
}
}
/**
* Create a new Socket within this context.
*
* @param type the socket type.
* @return the newly created Socket.
*/
public Socket socket(int type) {
return new Socket(this, type);
}
/**
* Create a new Poller within this context, with a default size.
*
* @return the newly created Poller.
* @deprecated use Poller constructor
*/
public Poller poller() {
return new Poller(this);
}
/**
* Create a new Poller within this context, with a specified initial size.
*
* @param size the poller initial size.
* @return the newly created Poller.
* @deprecated use Poller constructor
*/
public Poller poller(int size) {
return new Poller(this, size);
}
/**
* Class constructor.
*
* @param ioThreads size of the threads pool to handle I/O operations.
*/
protected Context(int ioThreads) {
construct(ioThreads);
}
/** Initialize the JNI interface */
protected native void construct(int ioThreads);
/** Free all resources used by JNI interface. */
protected native void destroy();
/**
* Get the underlying context handle. This is private because it is only accessed from JNI, where Java access
* controls are ignored.
*
* @return the internal 0MQ context handle.
*/
private long getContextHandle() {
return this.contextHandle;
}
/** Opaque data used by JNI driver. */
private long contextHandle;
public void close() {
term();
}
/**
* Sets the maximum number of sockets allowed on the context
*/
public native boolean setMaxSockets(int maxSockets);
/**
* The maximum number of sockets allowed on the context
*/
public native int getMaxSockets();
}
/**
* Inner class: Socket.
*/
public static class Socket implements Closeable {
private static native void nativeInit();
static {
if (!EmbeddedLibraryTools.LOADED_EMBEDDED_LIBRARY)
System.loadLibrary("jzmq");
nativeInit();
}
private final AtomicBoolean closed = new AtomicBoolean(false);
/**
* This is an explicit "destructor". It can be called to ensure the corresponding 0MQ Socket has been disposed
* of.
*/
public void close() {
if(closed.compareAndSet(false, true)) {
destroy();
}
}
/**
* The 'ZMQ_TYPE option shall retrieve the socket type for the specified 'socket'. The socket type is specified
* at socket creation time and cannot be modified afterwards.
*
* @return the socket type.
* @since 2.1.0
*/
public int getType() {
if (ZMQ.version_full() < ZMQ.make_version(2, 1, 0))
return -1;
return (int) getLongSockopt(TYPE);
}
/**
* @see #setLinger(long)
*
* @return the linger period.
* @since 2.1.0
*/
public long getLinger() {
if (ZMQ.version_full() < ZMQ.make_version(2, 1, 0))
return -1;
return getLongSockopt(LINGER);
}
/**
* @see #setReconnectIVL(long)
*
* @return the reconnectIVL.
* @since 3.0.0
*/
public long getReconnectIVL() {
if (ZMQ.version_full() < ZMQ.make_version(2, 1, 10))
return -1;
return getLongSockopt(RECONNECT_IVL);
}
/**
* @see #setBacklog(long)
*
* @return the backlog.
* @since 3.0.0
*/
public long getBacklog() {
if (ZMQ.version_full() < ZMQ.make_version(3, 0, 0))
return -1;
return getLongSockopt(BACKLOG);
}
/**
* @see #setReconnectIVLMax(long)
*
* @return the reconnectIVLMax.
* @since 3.0.0
*/
public long getReconnectIVLMax() {
if (ZMQ.version_full() < ZMQ.make_version(2, 1, 10))
return -1;
return getLongSockopt(RECONNECT_IVL_MAX);
}
/**
* @see #setMaxMsgSize(long)
*
* @return the maxMsgSize.
* @since 3.0.0
*/
public long getMaxMsgSize() {
if (ZMQ.version_full() < ZMQ.make_version(3, 0, 0))
return -1;
return getLongSockopt(MAXMSGSIZE);
}
/**
* @see #setSndHWM(long)
*
* @return the SndHWM.
* @since 3.0.0
*/
public long getSndHWM() {
if (ZMQ.version_full() < ZMQ.make_version(3, 0, 0))
return -1;
return getLongSockopt(SNDHWM);
}
/**
* @see #setRcvHWM(long)
*
* @return the recvHWM period.
* @since 3.0.0
*/
public long getRcvHWM() {
if (ZMQ.version_full() < ZMQ.make_version(3, 0, 0))
return -1;
return getLongSockopt(RCVHWM);
}
/**
* @see #setHWM(long)
*
* @return the High Water Mark.
*/
public long getHWM() {
if (ZMQ.version_full() >= ZMQ.make_version(3, 0, 0))
return -1;
return getLongSockopt(HWM);
}
/**
* @see #setSwap(long)
*
* @return the number of messages to swap at most.
*/
public long getSwap() {
if (ZMQ.version_full() >= ZMQ.make_version(3, 0, 0))
return -1;
return getLongSockopt(SWAP);
}
/**
* @see #setAffinity(long)
*
* @return the affinity.
*/
public long getAffinity() {
return getLongSockopt(AFFINITY);
}
/**
* @see #setTCPKeepAlive(long)
*
* @return the keep alive setting.
*/
public long getTCPKeepAliveSetting() {
if (ZMQ.version_full() < ZMQ.make_version(3, 2, 0))
return -1;
return getLongSockopt(KEEPALIVE);
}
/**
* @see #setTCPKeepAliveIdle(long)
*
* @return the keep alive idle value.
*/
public long getTCPKeepAliveIdle() {
if (ZMQ.version_full() < ZMQ.make_version(3, 2, 0))
return -1;
return getLongSockopt(KEEPALIVEIDLE);
}
/**
* @see #setTCPKeepAliveInterval(long)
*
* @return the keep alive interval.
*/
public long getTCPKeepAliveInterval() {
if (ZMQ.version_full() < ZMQ.make_version(3, 2, 0))
return -1;
return getLongSockopt(KEEPALIVEINTVL);
}
/**
* @see #setTCPKeepAliveCount(long)
*
* @return the keep alive count.
*/
public long getTCPKeepAliveCount() {
if (ZMQ.version_full() < ZMQ.make_version(3, 2, 0))
return -1;
return getLongSockopt(KEEPALIVECNT);
}
/**
* @see #setIdentity(byte[])
*
* @return the Identitiy.
*/
public byte[] getIdentity() {
return getBytesSockopt(IDENTITY);
}
/**
* @see #setRate(long)
*
* @return the Rate.
*/
public long getRate() {
return getLongSockopt(RATE);
}
/**
* @see #setRecoveryInterval(long)
*
* @return the RecoveryIntervall.
*/
public long getRecoveryInterval() {
return getLongSockopt(RECOVERY_IVL);
}
/**
* @see #setMulticastLoop(boolean)
*
* @return the Multicast Loop.
*/
public boolean hasMulticastLoop() {
if (ZMQ.version_full() < ZMQ.make_version(3, 0, 0))
return false;
return getLongSockopt(MCAST_LOOP) != 0;
}
/**
* Sets the time-to-live field in every multicast packet sent from this socket. The default is 1 which means
* that the multicast packets don't leave the local network.
*
* @param mcast_hops
*/
public void setMulticastHops(long mcast_hops) {
if (ZMQ.version_full() < ZMQ.make_version(3, 0, 0))
return;
setLongSockopt(MULTICAST_HOPS, mcast_hops);
}
/**
* @see #setMulticastHops(long)
*
* @return the Multicast Hops.
*/
public long getMulticastHops() {
if (ZMQ.version_full() < ZMQ.make_version(3, 0, 0))
return 1;
return getLongSockopt(MULTICAST_HOPS);
}
/**
* Sets the timeout for receive operation on the socket. If the value is 0, recv will return immediately, with a
* EAGAIN error if there is no message to receive. If the value is -1, it will block until a message is
* available. For all other values, it will wait for a message for that amount of time before returning with an
* EAGAIN error.
*
* @param timeout Timeout for receive operation in milliseconds. Default -1 (infinite)
*/
public void setReceiveTimeOut(int timeout) {
if (ZMQ.version_full() < ZMQ.make_version(2, 2, 0))
return;
setLongSockopt(RCVTIMEO, timeout);
}
/**
* @see #setReceiveTimeOut(int)
*
* @return the Receive Timeout in milliseconds
*/
public int getReceiveTimeOut() {
if (ZMQ.version_full() < ZMQ.make_version(2, 2, 0))
return -1;
return (int) getLongSockopt(RCVTIMEO);
}
/**
* Sets the timeout for send operation on the socket. If the value is 0, send will return immediately, with a
* EAGAIN error if the message cannot be sent. If the value is -1, it will block until the message is sent. For
* all other values, it will try to send the message for that amount of time before returning with an EAGAIN
* error.
*
* @param timeout Timeout for send operation in milliseconds. Default -1 (infinite)
*/
public void setSendTimeOut(int timeout) {
if (ZMQ.version_full() < ZMQ.make_version(2, 2, 0))
return;
setLongSockopt(SNDTIMEO, timeout);
}
/**
* @see #setSendTimeOut(int)
*
* @return the Send Timeout. in milliseconds
*/
public int getSendTimeOut() {
if (ZMQ.version_full() < ZMQ.make_version(2, 2, 0))
return -1;
return (int) getLongSockopt(SNDTIMEO);
}
/**
* @see #setSendBufferSize(long)
*
* @return the kernel send buffer size.
*/
public long getSendBufferSize() {
return getLongSockopt(SNDBUF);
}
/**
* @see #setReceiveBufferSize(long)
*
* @return the kernel receive buffer size.
*/
public long getReceiveBufferSize() {
return getLongSockopt(RCVBUF);
}
/**
* @see #setIPv4Only(boolean)
*
* @return the IPv4 only socket.
*/
public boolean getIPv4Only() {
return getLongSockopt(IPV4ONLY) == 1;
}
/**
* @see #setPlainServer(boolean)
*
* @return if the socket is setup for PLAIN security
*/
public boolean getPlainServer() {
if (ZMQ.version_full() >= ZMQ.make_version(4, 0, 0)) {
return getLongSockopt(PLAIN_SERVER) == 1;
}
return false;
}
/**
* @see #setPlainUsername(byte[])
*
* @return null terminated byte array in server charset
*/
public byte[] getPlainUsername() {
if (ZMQ.version_full() >= ZMQ.make_version(4, 0, 0)) {
return getBytesSockopt(PLAIN_USERNAME);
}
return null;
}
/**
* @see #setPlainPassword(byte[])
*
* @return null terminated byte array in server charset
*/
public byte[] getPlainPassword() {
if (ZMQ.version_full() >= ZMQ.make_version(4, 0, 0)) {
return getBytesSockopt(PLAIN_PASSWORD);
}
return null;
}
/**
* The 'ZMQ_RCVMORE' option shall return a boolean value indicating if the multi-part message currently being
* read from the specified 'socket' has more message parts to follow. If there are no message parts to follow or
* if the message currently being read is not a multi-part message a value of zero shall be returned. Otherwise,
* a value of 1 shall be returned.
*
* @return true if there are more messages to receive.
*/
public boolean hasReceiveMore() {
return getLongSockopt(RCVMORE) != 0;
}
/**
* The 'ZMQ_FD' option shall retrieve file descriptor associated with the 0MQ socket. The descriptor can be used
* to integrate 0MQ socket into an existing event loop. It should never be used for anything else than polling
* -- such as reading or writing. The descriptor signals edge-triggered IN event when something has happened
* within the 0MQ socket. It does not necessarily mean that the messages can be read or written. Check
* ZMQ_EVENTS option to find out whether the 0MQ socket is readable or writeable.
*
* @return the underlying file descriptor.
* @since 2.1.0
*/
public long getFD() {
if (ZMQ.version_full() < ZMQ.make_version(2, 1, 0))
return -1;
return getLongSockopt(FD);
}
/**
* The 'ZMQ_EVENTS' option shall retrieve event flags for the specified socket. If a message can be read from
* the socket ZMQ_POLLIN flag is set. If message can be written to the socket ZMQ_POLLOUT flag is set.
*
* @return the mask of outstanding events.
* @since 2.1.0
*/
public long getEvents() {
if (ZMQ.version_full() < ZMQ.make_version(2, 1, 0))
return -1;
return getLongSockopt(EVENTS);
}
/**
* The 'ZMQ_LINGER' option shall retrieve the period for pending outbound messages to linger in memory after
* closing the socket. Value of -1 means infinite. Pending messages will be kept until they are fully
* transferred to the peer. Value of 0 means that all the pending messages are dropped immediately when socket
* is closed. Positive value means number of milliseconds to keep trying to send the pending messages before
* discarding them.
*
* @param linger the linger period.
* @since 2.1.0
*/
public void setLinger(long linger) {
if (ZMQ.version_full() < ZMQ.make_version(2, 1, 0))
return;
setLongSockopt(LINGER, linger);
}
/**
* @since 3.0.0
*/
public void setReconnectIVL(long reconnectIVL) {
if (ZMQ.version_full() < ZMQ.make_version(2, 1, 10))
return;
setLongSockopt(RECONNECT_IVL, reconnectIVL);
}
/**
* @since 3.0.0
*/
public void setBacklog(long backlog) {
if (ZMQ.version_full() < ZMQ.make_version(3, 0, 0))
return;
setLongSockopt(BACKLOG, backlog);
}
/**
* @since 3.0.0
*/
public void setReconnectIVLMax(long reconnectIVLMax) {
if (ZMQ.version_full() < ZMQ.make_version(2, 1, 10))
return;
setLongSockopt(RECONNECT_IVL_MAX, reconnectIVLMax);
}
/**
* @since 3.0.0
*/
public void setMaxMsgSize(long maxMsgSize) {
if (ZMQ.version_full() < ZMQ.make_version(3, 0, 0))
return;
setLongSockopt(MAXMSGSIZE, maxMsgSize);
}
/**
* @since 3.0.0
*/
public void setSndHWM(long sndHWM) {
if (ZMQ.version_full() < ZMQ.make_version(3, 0, 0))
return;
setLongSockopt(SNDHWM, sndHWM);
}
/**
* @since 3.0.0
*/
public void setRcvHWM(long rcvHWM) {
if (ZMQ.version_full() < ZMQ.make_version(3, 0, 0))
return;
setLongSockopt(RCVHWM, rcvHWM);
}
/**
* The 'ZMQ_HWM' option shall set the high water mark for the specified 'socket'. The high water mark is a hard
* limit on the maximum number of outstanding messages 0MQ shall queue in memory for any single peer that the
* specified 'socket' is communicating with.
*
* If this limit has been reached the socket shall enter an exceptional state and depending on the socket type,
* 0MQ shall take appropriate action such as blocking or dropping sent messages. Refer to the individual socket
* descriptions in the man page of zmq_socket[3] for details on the exact action taken for each socket type.
*
* @param hwm the number of messages to queue.
*/
public void setHWM(long hwm) {
if (ZMQ.version_full() >= ZMQ.make_version(3, 0, 0))
return;
setLongSockopt(HWM, hwm);
}
/**
* Get the Swap. The 'ZMQ_SWAP' option shall set the disk offload (swap) size for the specified 'socket'. A
* socket which has 'ZMQ_SWAP' set to a non-zero value may exceed its high water mark; in this case outstanding
* messages shall be offloaded to storage on disk rather than held in memory.
*
* @param swap The value of 'ZMQ_SWAP' defines the maximum size of the swap space in bytes.
*/
public void setSwap(long swap) {
if (ZMQ.version_full() >= ZMQ.make_version(3, 0, 0))
return;
setLongSockopt(SWAP, swap);
}
/**
* Get the Affinity. The 'ZMQ_AFFINITY' option shall set the I/O thread affinity for newly created connections
* on the specified 'socket'.
*
* Affinity determines which threads from the 0MQ I/O thread pool associated with the socket's _context_ shall
* handle newly created connections. A value of zero specifies no affinity, meaning that work shall be
* distributed fairly among all 0MQ I/O threads in the thread pool. For non-zero values, the lowest bit
* corresponds to thread 1, second lowest bit to thread 2 and so on. For example, a value of 3 specifies that
* subsequent connections on 'socket' shall be handled exclusively by I/O threads 1 and 2.
*
* See also in the man page of zmq_init[3] for details on allocating the number of I/O threads for a specific
* _context_.
*
* @param affinity the affinity.
*/
public void setAffinity(long affinity) {
setLongSockopt(AFFINITY, affinity);
}
/**
* Override SO_KEEPALIVE socket option (where supported by OS) to enable keep-alive packets for a socket
* connection. Possible values are -1, 0, 1. The default value -1 will skip all overrides and do the OS default.
*
* @param optVal The value of 'ZMQ_TCP_KEEPALIVE' to turn TCP keepalives on (1) or off (0).
*/
public void setTCPKeepAlive(long optVal) {
if (ZMQ.version_full() >= ZMQ.make_version(3, 2, 0))
setLongSockopt(KEEPALIVE, optVal);
}
/**
* Override TCP_KEEPCNT socket option (where supported by OS). The default value -1 will skip all overrides and
* do the OS default.
*
* @param optVal The value of 'ZMQ_TCP_KEEPALIVE_CNT' defines the number of keepalives before death.
*/
public void setTCPKeepAliveCount(long optVal) {
if (ZMQ.version_full() >= ZMQ.make_version(3, 2, 0))
setLongSockopt(KEEPALIVECNT, optVal);
}
/**
* Override TCP_KEEPINTVL socket option (where supported by OS). The default value -1 will skip all overrides
* and do the OS default.
*
* @param optVal The value of 'ZMQ_TCP_KEEPALIVE_INTVL' defines the interval between keepalives. Unit is OS
* dependant.
*/
public void setTCPKeepAliveInterval(long optVal) {
if (ZMQ.version_full() >= ZMQ.make_version(3, 2, 0))
setLongSockopt(KEEPALIVEINTVL, optVal);
}
/**
* Override TCP_KEEPCNT (or TCP_KEEPALIVE on some OS) socket option (where supported by OS). The default value
* -1 will skip all overrides and do the OS default.
*
* @param optVal The value of 'ZMQ_TCP_KEEPALIVE_IDLE' defines the interval between the last data packet sent
* over the socket and the first keepalive probe. Unit is OS dependant.
*/
public void setTCPKeepAliveIdle(long optVal) {
if (ZMQ.version_full() >= ZMQ.make_version(3, 2, 0))
setLongSockopt(KEEPALIVEIDLE, optVal);
}
/**
* The 'ZMQ_IDENTITY' option shall set the identity of the specified 'socket'. Socket identity determines if
* existing 0MQ infastructure (_message queues_, _forwarding devices_) shall be identified with a specific
* application and persist across multiple runs of the application.
*
* If the socket has no identity, each run of an application is completely separate from other runs. However,
* with identity set the socket shall re-use any existing 0MQ infrastructure configured by the previous run(s).
* Thus the application may receive messages that were sent in the meantime, _message queue_ limits shall be
* shared with previous run(s) and so on.
*
* Identity should be at least one byte and at most 255 bytes long. Identities starting with binary zero are
* reserved for use by 0MQ infrastructure.
*
* @param identity
*/
public void setIdentity(byte[] identity) {
setBytesSockopt(IDENTITY, identity);
}
/**
* The 'ZMQ_SUBSCRIBE' option shall establish a new message filter on a 'ZMQ_SUB' socket. Newly created
* 'ZMQ_SUB' sockets shall filter out all incoming messages, therefore you should call this option to establish
* an initial message filter.
*
* An empty 'option_value' of length zero shall subscribe to all incoming messages. A non-empty 'option_value'
* shall subscribe to all messages beginning with the specified prefix. Mutiple filters may be attached to a
* single 'ZMQ_SUB' socket, in which case a message shall be accepted if it matches at least one filter.
*
* @param topic
*/
public void subscribe(byte[] topic) {
setBytesSockopt(SUBSCRIBE, topic);
}
/**
* The 'ZMQ_UNSUBSCRIBE' option shall remove an existing message filter on a 'ZMQ_SUB' socket. The filter
* specified must match an existing filter previously established with the 'ZMQ_SUBSCRIBE' option. If the socket
* has several instances of the same filter attached the 'ZMQ_UNSUBSCRIBE' option shall remove only one
* instance, leaving the rest in place and functional.
*
* @param topic
*/
public void unsubscribe(byte[] topic) {
setBytesSockopt(UNSUBSCRIBE, topic);
}
/**
* The 'ZMQ_RATE' option shall set the maximum send or receive data rate for multicast transports such as in the
* man page of zmq_pgm[7] using the specified 'socket'.
*
* @param rate
*/
public void setRate(long rate) {
setLongSockopt(RATE, rate);
}
/**
* The 'ZMQ_RECOVERY_IVL' option shall set the recovery interval for multicast transports using the specified
* 'socket'. The recovery interval determines the maximum time in seconds (before version 3.0.0) or milliseconds
* (version 3.0.0 and after) that a receiver can be absent from a multicast group before unrecoverable data loss
* will occur.
*
* CAUTION: Exercise care when setting large recovery intervals as the data needed for recovery will be held in
* memory. For example, a 1 minute recovery interval at a data rate of 1Gbps requires a 7GB in-memory buffer.
* {Purpose of this Method}
*
* @param recovery_ivl
*/
public void setRecoveryInterval(long recovery_ivl) {
setLongSockopt(RECOVERY_IVL, recovery_ivl);
}
/**
* The 'ZMQ_MCAST_LOOP' option shall control whether data sent via multicast transports using the specified
* 'socket' can also be received by the sending host via loopback. A value of zero disables the loopback
* functionality, while the default value of 1 enables the loopback functionality. Leaving multicast loopback
* enabled when it is not required can have a negative impact on performance. Where possible, disable
* 'ZMQ_MCAST_LOOP' in production environments.
*
* @param mcast_loop
*/
public void setMulticastLoop(boolean mcast_loop) {
if (ZMQ.version_full() >= ZMQ.make_version(3, 0, 0))
return;
setLongSockopt(MCAST_LOOP, mcast_loop ? 1 : 0);
}
/**
* The 'ZMQ_SNDBUF' option shall set the underlying kernel transmit buffer size for the 'socket' to the
* specified size in bytes. A value of zero means leave the OS default unchanged. For details please refer to
* your operating system documentation for the 'SO_SNDBUF' socket option.
*
* @param sndbuf
*/
public void setSendBufferSize(long sndbuf) {
setLongSockopt(SNDBUF, sndbuf);
}
/**
* The 'ZMQ_RCVBUF' option shall set the underlying kernel receive buffer size for the 'socket' to the specified
* size in bytes. A value of zero means leave the OS default unchanged. For details refer to your operating
* system documentation for the 'SO_RCVBUF' socket option.
*
* @param rcvbuf
*/
public void setReceiveBufferSize(long rcvbuf) {
setLongSockopt(RCVBUF, rcvbuf);
}
/**
* The 'ZMQ_IPV4ONLY' option shall set the underlying native socket type. An IPv6 socket lets applications
* connect to and accept connections from both IPv4 and IPv6 hosts.
*
* @param v4only A value of true will use IPv4 sockets, while the value of false will use IPv6 sockets
*/
public void setIPv4Only(boolean v4only) {
setLongSockopt(IPV4ONLY, v4only ? 1L : 0L);
}
/**
* Sets the ROUTER socket behavior when an unroutable message is encountered.
*
* @param mandatory A value of false is the default and discards the message silently when it cannot be routed.
* A value of true returns an EHOSTUNREACH error code if the message cannot be routed.
*/
public void setRouterMandatory(boolean mandatory) {
setLongSockopt(ROUTER_MANDATORY, mandatory ? 1L : 0L);
}
/**
* Sets the XPUB socket behavior on new subscriptions and unsubscriptions.
*
* @param verbose A value of false is the default and passes only new subscription messages to upstream.
* A value of true passes all subscription messages upstream.
* @since 3.2.2
*/
public void setXpubVerbose(boolean verbose) {
if (ZMQ.version_full() < ZMQ.make_version(3, 2, 2))
return;
setLongSockopt(XPUB_VERBOSE, verbose ? 1L : 0L);
}
/**
* Sets if the socket is for a server using the PLAIN security mechanism.
* @see PLAIN RFC
* @param plain whether or not to use PLAIN security
* @since 4.0.0
*/
public void setPlainServer(boolean plain) {
if (ZMQ.version_full() >= ZMQ.make_version(4, 0, 0)) {
setLongSockopt(PLAIN_SERVER, plain ? 1L : 0L);
}
}
/**
* Sets the username used for the PLAIN security mechanism.
* @see PLAIN RFC
* @param username null terminated string in server charset
* @since 4.0.0
*/
public void setPlainUsername(byte[] username) {
if (ZMQ.version_full() >= ZMQ.make_version(4, 0, 0)) {
setBytesSockopt(PLAIN_USERNAME, username);
}
}
/**
* Sets the password used for the PLAIN security mechanism.
* @see PLAIN RFC
* @param password null terminated string in server charset
* @since 4.0.0
*/
public void setPlainPassword(byte[] password) {
if (ZMQ.version_full() >= ZMQ.make_version(4, 0, 0)) {
setBytesSockopt(PLAIN_PASSWORD, password);
}
}
/**
* Sets the domain for ZAP (ZMQ RFC 27) authentication.
* @param domain For NULL security (the default on all tcp:// connections),
* ZAP authentication only happens if you set a non-empty domain. For PLAIN and CURVE security,
* ZAP requests are always made, if there is a ZAP handler present.
* See http://rfc.zeromq.org/spec:27 for more details.
*/
public void setZAPDomain(byte[] domain) {
if(ZMQ.version_full() >= ZMQ.make_version(4, 1, 0)) {
setBytesSockopt(ZAP_DOMAIN, domain);
}
}
public void setGSSAPIServer(boolean isServer) {
if(ZMQ.version_full() >= ZMQ.makeVersion(4, 1, 0)) {
setLongSockopt(GSSAPI_SERVER, isServer ? 1L : 0L);
}
}
public void setGSSAPIPrincipal(byte[] principal) {
if(ZMQ.version_full() >= ZMQ.make_version(4, 1, 0)) {
setBytesSockopt(GSSAPI_PRINCIPAL, principal);
}
}
public void setGSSAPIServicePrincipal(byte[] principal) {
if(ZMQ.version_full() >= ZMQ.make_version(4, 1, 0)) {
setBytesSockopt(GSSAPI_SERVICE_PRINCIPAL, principal);
}
}
public void setGSSAPIPlainText(boolean isPlaintext) {
if(ZMQ.version_full() >= ZMQ.makeVersion(4, 1, 0)) {
setLongSockopt(GSSAPI_PLAINTEXT, isPlaintext ? 1L : 0L);
}
}
/**
* Sets whether socket should keep only last received/to be sent message in its inbound/outbound queue.
*
* @param conflate A value of false is the default which means socket preserves all messages with respect
* to the RECVHWM and SENDHWM options. A value of true means only last message is kept ignoring
* the RECVHWM and SENDHWM options.
* @since 4.0.0
*/
public void setConflate(boolean conflate) {
if (ZMQ.version_full() >= ZMQ.make_version(4, 0, 0)) {
setLongSockopt(CONFLATE, conflate ? 1L : 0L);
}
}
/**
* Indicate whether socket should keep only last received/to be sent message in its inbound/outbound queue.
*
* @return true if should keep only last received/to be sent message in its inbound/outbound queue.
* @since 4.0.0
*/
public boolean getConflate() {
if (ZMQ.version_full() >= ZMQ.make_version(4, 0, 0)) {
return getLongSockopt(CONFLATE) != 0L;
}
else {
return false;
}
}
/**
* Indicate whether socket should only queue messages to completed connections.
*
* @return true if should only queue messages to completed connections.
* @since 3.2.0
*/
public boolean getImmediate() {
if (ZMQ.version_full() >= ZMQ.make_version(3, 2, 0)) {
return getLongSockopt(IMMEDIATE) != 0L;
}
else {
return false;
}
}
/**
* Sets whether socket should only queue messages to completed connections.
*
* @param immediate A value of false is the default which means socket will not queue messages to
* to incomplete connections. This will cause the socket to block if there are no other connections,
* but will prevent queues from filling on pipes awaiting connection.
* @since 3.2.0
*/
public void setImmediate(boolean immediate) {
if (ZMQ.version_full() >= ZMQ.make_version(3, 2, 0)) {
setLongSockopt(IMMEDIATE, immediate ? 1L : 0L);
}
}
public void setReqRelaxed(boolean isRelaxed) {
if (ZMQ.version_full() >= ZMQ.make_version(4, 0, 0)) {
setLongSockopt(REQ_RELAXED, isRelaxed ? 1L : 0L);
}
}
public void setReqCorrelate(boolean isCorrelate) {
if (ZMQ.version_full() >= ZMQ.make_version(4, 0, 0)) {
setLongSockopt(REQ_CORRELATE, isCorrelate ? 1L : 0L);
}
}
/**
* Sets whether the socket should automatically send an empty message
* when a new connection is made or accepted. This may be set on
* REQ, DEALER, or ROUTER sockets connected to a ROUTER socket.
* The application must filter such empty messages.
*
* @param isProbeRouter if {@code true}, the socket will automatically
* send an empty message when a new connection is made or
* accepted; if {@code false}, no such message will be sent
* @since 4.0.0
*/
public void setProbeRouter(boolean isProbeRouter) {
if (ZMQ.version_full() >= ZMQ.make_version(4, 0, 0)) {
setLongSockopt(PROBE_ROUTER, isProbeRouter ? 1L : 0L);
}
}
/**
* Bind to network interface. Start listening for new connections.
*
* @param addr the endpoint to bind to.
*/
public native void bind(String addr);
/**
* Bind to network interface to a random port. Start listening for new connections.
*
* @param addr the endpoint to bind to.
*/
public int bindToRandomPort(String addr) {
return bindToRandomPort(addr, 2000, 20000, 100);
}
/**
* Bind to network interface to a random port. Start listening for new connections.
*
* @param addr the endpoint to bind to.
* @param min_port The minimum port in the range of ports to try.
*/
public int bindToRandomPort(String addr, int min_port) {
return bindToRandomPort(addr, min_port, 20000, 100);
}
/**
* Bind to network interface to a random port. Start listening for new connections.
*
* @param addr the endpoint to bind to.
* @param min_port The minimum port in the range of ports to try.
* @param max_port The maximum port in the range of ports to try.
*/
public int bindToRandomPort(String addr, int min_port, int max_port) {
return bindToRandomPort(addr, min_port, max_port, 100);
}
/**
* Bind to network interface to a random port. Start listening for new connections.
*
* @param addr the endpoint to bind to.
* @param min_port The minimum port in the range of ports to try.
* @param max_port The maximum port in the range of ports to try.
* @param max_tries The number of attempt to bind.
*/
public int bindToRandomPort(String addr, int min_port, int max_port, int max_tries) {
int port;
Random rand = new Random();
for (int i = 0; i < max_tries; i++) {
port = rand.nextInt(max_port - min_port + 1) + min_port;
try {
bind(String.format("%s:%s", addr, port));
return port;
} catch (ZMQException e) {
if (e.getErrorCode() != ZMQ.EADDRINUSE()) {
throw e;
}
continue;
}
}
throw new ZMQException("Could not bind socket to random port.", (int) ZMQ.EADDRINUSE());
}
/**
* Unbind from network interface. Stop listening for connections.
*
* @param addr the endpoint to unbind from.
*/
public native void unbind(String addr);
/**
* Connect to remote application.
*
* @param addr the endpoint to connect to.
*/
public native void connect(String addr);
/**
* Disconnect from a remote application.
*
* @param addr the endpoint to disconnect from.
*/
public native void disconnect(String addr);
/**
* Start a monitoring socket where events can be received.
*
* @param addr the endpoint to receive events from. (must be inproc transport)
* @param events the events of interest.
* @return true if monitor socket setup is successful
* @throws ZMQException
*/
public native boolean monitor(String addr, int events) throws ZMQException;
/**
* Send a message.
*
* @param msg the message to send, as an array of bytes.
* @param offset the offset of the message to send.
* @param flags the flags to apply to the send operation.
* @return true if send was successful, false otherwise.
*/
public boolean send(byte[] msg, int offset, int flags) {
return send(msg, offset, msg.length, flags);
}
/**
*
* @param msg
* @param offset
* @param len
* @param flags
* @return
*/
public native boolean send(byte[] msg, int offset, int len, int flags);
/**
* Perform a zero copy send. The buffer must be allocated using ByteBuffer.allocateDirect
*
* @param buffer
* @param len
* @param flags
* @return
*/
public native boolean sendZeroCopy(ByteBuffer buffer, int len, int flags);
/**
* Send a message.
*
* @param msg the message to send, as an array of bytes.
* @param flags the flags to apply to the send operation.
* @return true if send was successful, false otherwise.
*/
public boolean send(byte[] msg, int flags) {
return send(msg, 0, msg.length, flags);
}
/**
* Send a String.
*
* @param msg the message to send, as a String.
* @return true if send was successful, false otherwise.
*/
public boolean send(String msg) {
byte[] b = msg.getBytes();
return send(b, 0, b.length, 0);
}
/**
* Send a String.
*
* @param msg the message to send, as a String.
* @return true if send was successful, false otherwise.
*/
public boolean sendMore(String msg) {
byte[] b = msg.getBytes();
return send(b, 0, b.length, SNDMORE);
}
/**
* Send a String.
*
* @param msg the message to send, as a String.
* @param flags the flags to apply to the send operation.
* @return true if send was successful, false otherwise.
*/
public boolean send(String msg, int flags) {
byte[] b = msg.getBytes();
return send(b, 0, b.length, flags);
}
/**
* Send a message
*
* @param bb ByteBuffer payload
* @param flags the flags to apply to the send operation
* @return the number of bytes sent
*/
public native int sendByteBuffer(ByteBuffer bb, int flags);
/**
* Receive a message.
*
* @param flags the flags to apply to the receive operation.
* @return the message received, as an array of bytes; null on error.
*/
public native byte[] recv(int flags);
/**
* Receive a message in to a specified buffer.
*
* @param buffer byte[] to copy zmq message payload in to.
* @param offset offset in buffer to write data
* @param len max bytes to write to buffer. If len is smaller than the incoming message size, the message will
* be truncated.
* @param flags the flags to apply to the receive operation.
* @return the number of bytes read, -1 on error
*/
public native int recv(byte[] buffer, int offset, int len, int flags);
/**
* Zero copy recv
*
* @param buffer
* @param len
* @param flags
* @return bytes read, -1 on error
*/
public native int recvZeroCopy(ByteBuffer buffer, int len, int flags);
/**
* Receive a message.
*
* @return the message received, as an array of bytes; null on error.
*/
public byte[] recv() {
return recv(0);
}
/**
* Receive a message as a String with the default Charset.
*
* @deprecated use {@link #recvStr(Charset)} instead.
* @return the message received, as a String; null on error.
*/
@Deprecated
public String recvStr() {
return recvStr(0);
}
/**
* Receive a message as a String with a given Charset.
*
* @param charset the charset of the resulting string.
* @return the message received, as a String; null on error.
*/
public String recvStr(Charset charset) {
return recvStr(0, charset);
}
/**
* Receive a message as a String with the default charset.
*
* @deprecated use {@link #recvStr(int, Charset)} instead.
* @param flags the flags to apply to the receive operation.
* @return the message received, as a String; null on error.
*/
@Deprecated
public String recvStr(int flags) {
return recvStr(flags, Charset.defaultCharset());
}
/**
* Receive a message as a String.
*
* @param flags the flags to apply to the receive operation.
* @param charset the charset of the resulting string.
* @return the message received, as a String; null on error.
*/
public String recvStr(int flags, Charset charset) {
byte[] data = recv(flags);
if (data == null) {
return null;
} else {
return new String(data, charset);
}
}
/**
* Receive a message
*
* @param buffer
* @param flags
* @return bytes read, -1 on error
*/
public native int recvByteBuffer(ByteBuffer buffer, int flags);
/**
* Class constructor.
*
* @param context a 0MQ context previously created.
* @param type the socket type.
*/
protected Socket(Context context, int type) {
// We keep a local handle to context so that
// garbage collection won't be too greedy on it.
this.context = context;
construct(context, type);
}
/** Initialize the JNI interface */
protected native void construct(Context ctx, int type);
/** Free all resources used by JNI interface. */
protected native void destroy();
/**
* Get the socket option value, as a long.
*
* @param option ID of the option to set.
* @return The socket option value (as a long).
*/
protected native long getLongSockopt(int option);
/**
* Get the socket option value, as a byte array.
*
* @param option ID of the option to set.
* @return The socket option value (as a byte array).
*/
protected native byte[] getBytesSockopt(int option);
/**
* Set the socket option value, given as a long.
*
* @param option ID of the option to set.
* @param optval value (as a long) to set the option to.
*/
protected native void setLongSockopt(int option, long optval);
/**
* Set the socket option value, given as a byte array.
*
* @param option ID of the option to set.
* @param optval value (as a byte array) to set the option to.
*/
protected native void setBytesSockopt(int option, byte[] optval);
/**
* Get the underlying socket handle. This is private because it is only accessed from JNI, where Java access
* controls are ignored.
*
* @return the internal 0MQ socket handle.
*/
private long getSocketHandle() {
return this.socketHandle;
}
/** Opaque data used by JNI driver. */
private long socketHandle;
private final Context context;
// private Constants use the appropriate setter instead.
private static final int HWM = 1;
// public static final int LWM = 2; // No longer supported
private static final int SWAP = 3;
private static final int AFFINITY = 4;
private static final int IDENTITY = 5;
private static final int SUBSCRIBE = 6;
private static final int UNSUBSCRIBE = 7;
private static final int RATE = 8;
private static final int RECOVERY_IVL = 9;
private static final int MCAST_LOOP = 10;
private static final int SNDBUF = 11;
private static final int RCVBUF = 12;
private static final int RCVMORE = 13;
private static final int FD = 14;
private static final int EVENTS = 15;
private static final int TYPE = 16;
private static final int LINGER = 17;
private static final int RECONNECT_IVL = 18;
private static final int BACKLOG = 19;
private static final int RECONNECT_IVL_MAX = 21;
private static final int MAXMSGSIZE = 22;
private static final int SNDHWM = 23;
private static final int RCVHWM = 24;
private static final int MULTICAST_HOPS = 25;
private static final int RCVTIMEO = 27;
private static final int SNDTIMEO = 28;
private static final int IPV4ONLY = 31;
private static final int ROUTER_MANDATORY = 33;
private static final int KEEPALIVE = 34;
private static final int KEEPALIVECNT = 35;
private static final int KEEPALIVEIDLE = 36;
private static final int KEEPALIVEINTVL = 37;
private static final int IMMEDIATE = 39;
private static final int XPUB_VERBOSE = 40;
private static final int PLAIN_SERVER = 44;
private static final int PLAIN_USERNAME = 45;
private static final int PLAIN_PASSWORD = 46;
private static final int PROBE_ROUTER = 51;
private static final int REQ_CORRELATE = 52;
private static final int REQ_RELAXED = 53;
private static final int CONFLATE = 54;
private static final int ZAP_DOMAIN = 55;
private static final int GSSAPI_SERVER = 62;
private static final int GSSAPI_PRINCIPAL = 63;
private static final int GSSAPI_SERVICE_PRINCIPAL = 64;
private static final int GSSAPI_PLAINTEXT = 65;
}
public static class PollItem {
private Socket socket;
private SelectableChannel channel;
private int events;
private int revents;
public PollItem(Socket socket, int events) {
this.socket = socket;
this.events = events;
this.revents = 0;
}
public PollItem(SelectableChannel channel, int events) {
this.channel = channel;
this.events = events;
this.revents = 0;
}
public SelectableChannel getRawSocket() {
return channel;
}
public Socket getSocket() {
return socket;
}
public boolean isError() {
return (revents & Poller.POLLERR) > 0;
}
public int readyOps() {
return revents;
}
public boolean isReadable() {
return (revents & Poller.POLLIN) > 0;
}
public boolean isWritable() {
return (revents & Poller.POLLOUT) > 0;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof PollItem))
return false;
PollItem target = (PollItem) obj;
if (socket != null && socket == target.socket)
return true;
if (channel != null && channel == target.channel)
return true;
return false;
}
}
/**
* Inner class: Poller.
*/
public static class Poller {
/**
* These values can be ORed to specify what we want to poll for.
*/
public static final int POLLIN = 1;
public static final int POLLOUT = 2;
public static final int POLLERR = 4;
/**
* Register a Socket for polling on all events.
*
* @param socket the Socket we are registering.
* @return the index identifying this Socket in the poll set.
*/
public int register(Socket socket) {
return register(socket, POLLIN | POLLOUT | POLLERR);
}
/**
* Register a Channel for polling on all events.
*
* @param channel the Channel we are registering.
* @return the index identifying this Channel in the poll set.
*/
public int register(SelectableChannel channel) {
return register(channel, POLLIN | POLLOUT | POLLERR);
}
/**
* Register a Socket for polling on the specified events.
*
* Automatically grow the internal representation if needed.
*
* @param socket the Socket we are registering.
* @param events a mask composed by XORing POLLIN, POLLOUT and POLLERR.
* @return the index identifying this Socket in the poll set.
*/
public int register(Socket socket, int events) {
return registerInternal(new PollItem(socket, events));
}
/**
* Register a Channel for polling on the specified events.
*
* Automatically grow the internal representation if needed.
*
* @param channel the Channel we are registering.
* @param events a mask composed by XORing POLLIN, POLLOUT and POLLERR.
* @return the index identifying this Channel in the poll set.
*/
public int register(SelectableChannel channel, int events) {
return registerInternal(new PollItem(channel, events));
}
/**
* Register a Channel for polling on the specified events.
*
* Automatically grow the internal representation if needed.
*
* @param item the PollItem we are registering.
* @return the index identifying this Channel in the poll set.
*/
public int register(PollItem item) {
return registerInternal(item);
}
/**
* Register a Socket for polling on the specified events.
*
* Automatically grow the internal representation if needed.
*
* @param item the PollItem we are registering.
* @return the index identifying this Socket in the poll set.
*/
private int registerInternal(PollItem item) {
int pos = -1;
if (!this.freeSlots.isEmpty()) {
// If there are free slots in our array, remove one
// from the free list and use it.
pos = this.freeSlots.remove();
} else {
if (this.next >= this.size) {
// It is necessary to grow the arrays.
// Compute new size for internal arrays.
int nsize = this.size + SIZE_INCREMENT;
// Create new internal arrays.
PollItem[] ns = new PollItem[nsize];
short[] ne = new short[nsize];
short[] nr = new short[nsize];
// Copy contents of current arrays into new arrays.
for (int i = 0; i < this.next; ++i) {
ns[i] = this.items[i];
}
// Swap internal arrays and size to new values.
this.size = nsize;
this.items = ns;
}
pos = this.next++;
}
this.items[pos] = item;
this.used++;
return pos;
}
/**
* Unregister a Socket for polling on the specified events.
*
* @param socket the Socket to be unregistered
*/
public void unregister(Socket socket) {
unregisterInternal(socket);
}
/**
* Unregister a Channel for polling on the specified events.
*
* @param channel the Channel to be unregistered
*/
public void unregister(SelectableChannel channel) {
unregisterInternal(channel);
}
/**
* Unregister a Socket for polling on the specified events.
*
* @param socket the Socket to be unregistered
*/
private void unregisterInternal(Object socket) {
for (int i = 0; i < this.next; ++i) {
PollItem item = this.items[i];
if (item == null) {
continue;
}
if (item.socket == socket || item.channel == socket) {
this.items[i] = null;
this.freeSlots.add(i);
--this.used;
break;
}
}
}
/**
* Get the socket associated with an index.
*
* @param index the desired index.
* @return the Socket associated with that index (or null).
*/
public Socket getSocket(int index) {
if (index < 0 || index >= this.next)
return null;
return this.items[index].socket;
}
/**
* Get the PollItem associated with an index.
*
* @param index the desired index.
* @return the PollItem associated with that index (or null).
*/
public PollItem getItem(int index) {
if (index < 0 || index >= this.next)
return null;
return this.items[index];
}
/**
* Get the current poll timeout.
*
* @return the current poll timeout in microseconds.
* @deprecated Timeout handling has been moved to the poll() methods.
*/
public long getTimeout() {
return this.timeout;
}
/**
* Set the poll timeout.
*
* @param timeout the desired poll timeout in microseconds.
* @deprecated Timeout handling has been moved to the poll() methods.
*/
public void setTimeout(long timeout) {
if (timeout < -1)
return;
this.timeout = timeout;
}
/**
* Get the current poll set size.
*
* @return the current poll set size.
*/
public int getSize() {
return this.size;
}
/**
* Get the index for the next position in the poll set size.
*
* @return the index for the next position in the poll set size.
*/
public int getNext() {
return this.next;
}
/**
* Issue a poll call. If the poller's internal timeout value has been set, use that value as timeout; otherwise,
* block indefinitely.
*
* @return how many objects where signalled by poll ().
*/
public long poll() {
long tout = -1;
if (this.timeout > -1) {
tout = this.timeout;
}
return poll(tout);
}
/**
* Issue a poll call, using the specified timeout value.
*
* Since ZeroMQ 3.0, the timeout parameter is in milliseconds,
* but prior to this the unit was microseconds.
*
* @param tout the timeout, as per zmq_poll if -1, it will block
* indefinitely until an event happens; if 0, it will
* return immediately; otherwise, it will wait for at most
* that many milliseconds/microseconds (see above).
*
* @see 2.1 docs
* @see 3.0 docs
*
* @return how many objects where signalled by poll ()
*/
public int poll(long tout) {
if (tout < -1) {
return 0;
}
if (this.size <= 0 || this.next <= 0) {
return 0;
}
return run_poll(this.items, this.used, tout);
}
/**
* Check whether the specified element in the poll set was signalled for input.
*
* @param index
*
* @return true if the element was signalled.
*/
public boolean pollin(int index) {
return poll_mask(index, POLLIN);
}
/**
* Check whether the specified element in the poll set was signalled for output.
*
* @param index
*
* @return true if the element was signalled.
*/
public boolean pollout(int index) {
return poll_mask(index, POLLOUT);
}
/**
* Check whether the specified element in the poll set was signalled for error.
*
* @param index
*
* @return true if the element was signalled.
*/
public boolean pollerr(int index) {
return poll_mask(index, POLLERR);
}
/**
* Constructor
*
* @param size the number of Sockets this poller will contain.
*/
public Poller(int size) {
this(null, size);
}
/**
* Class constructor.
*
* @param context a 0MQ context previously created.
*/
protected Poller(Context context) {
this(context, SIZE_DEFAULT);
}
/**
* Class constructor.
*
* @param context a 0MQ context previously created.
* @param size the number of Sockets this poller will contain.
*/
protected Poller(Context context, int size) {
this.context = context;
this.size = size;
this.next = 0;
this.items = new PollItem[this.size];
freeSlots = new LinkedList();
}
/**
* Issue a poll call on the specified 0MQ items.
*
* Since ZeroMQ 3.0, the timeout parameter is in milliseconds, but prior to this the unit was
* microseconds.
*
* @param items an array of PollItem to poll.
* @param timeout the maximum timeout in milliseconds/microseconds (see above).
* @return how many objects where signalled by poll.
* @see 2.1 docs
* @see 3.0 docs
*/
protected native static int run_poll(PollItem[] items, int count, long timeout);
/**
* Check whether a specific mask was signalled by latest poll call.
*
* @param index the index indicating the socket.
* @param mask a combination of POLLIN, POLLOUT and POLLERR.
* @return true if specific socket was signalled as specified.
*/
private boolean poll_mask(int index, int mask) {
if (mask <= 0 || index < 0 || index >= this.next || this.items[index] == null) {
return false;
}
return (this.items[index].revents & mask) > 0;
}
private Context context = null;
private long timeout = -2; // mark as uninitialized
private int size = 0;
private int next = 0;
private int used = 0;
private PollItem[] items = null;
// When socket is removed from polling, store free slots here
private LinkedList freeSlots = null;
private static final int SIZE_DEFAULT = 32;
private static final int SIZE_INCREMENT = 16;
}
/**
* Inner class: Event.
* Monitor socket event class
*/
public static class Event {
private static native void nativeInit();
static {
nativeInit();
}
private final int event;
private final Object value;
private final String address;
private Event(int event, int value, String address) {
this(event, Integer.valueOf(value), address != null ? address : "");
}
public Event(int event, Object value, String address) {
this.event = event;
this.value = value;
this.address = address;
}
public int getEvent() {
return event;
}
public Object getValue() {
return value;
}
/**
* Get the address.
* For libzmq versions 3.2.x the address will be an empty string.
* @return
*/
public String getAddress() {
return address;
}
private static native Event recv(long socket, int flags) throws ZMQException;
/**
* Receive an event from a monitor socket.
* For libzmq versions 3.2.x the address will be an empty string.
* @param socket the socket
* @param flags the flags to apply to the receive operation.
* @return the received event or null if no message was received.
* @throws ZMQException
*/
public static Event recv(Socket socket, int flags) throws ZMQException {
return Event.recv(socket.socketHandle, flags);
}
/**
* Receive an event from a monitor socket.
* Does a blocking recv.
* For libzmq versions 3.2.x the address will be an empty string.
* @param socket the socket
* @return the received event.
* @throws ZMQException
*/
public static Event recv(Socket socket) throws ZMQException {
return Event.recv(socket, 0);
}
}
}