All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.zeromq.ZMQ Maven / Gradle / Ivy

The newest version!
/*
  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); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy