Пример #1
0
int zmq_curve_public (char *z85_public_key, const char *z85_secret_key)
{
#if defined (ZMQ_HAVE_CURVE)
#   if crypto_box_PUBLICKEYBYTES != 32 \
    || crypto_box_SECRETKEYBYTES != 32
#       error "CURVE encryption library not built correctly"
#   endif

    uint8_t public_key[32];
    uint8_t secret_key[32];

    if (zmq_z85_decode (secret_key, z85_secret_key) == NULL)
        return -1;

    // Return codes are suppressed as none of these can actually fail.
    crypto_scalarmult_base (public_key, secret_key);
    zmq_z85_encode (z85_public_key, public_key, 32);

    return 0;
#else
    (void) z85_public_key, (void) z85_secret_key;
    errno = ENOTSUP;
    return -1;
#endif
}
Пример #2
0
void test__zmq_z85_decode__invalid__failure (const char (&encoded_)[SIZE])
{
    uint8_t decoded[SIZE * 4 / 5 + 1];
    errno = 0;
    assert (zmq_z85_decode (decoded, encoded_) == NULL);
    assert (zmq_errno () == EINVAL);
}
Пример #3
0
zcert_t *
zcert_load (char *format, ...)
{
#if (ZMQ_VERSION_MAJOR == 4)
    assert (format);
    va_list argptr;
    va_start (argptr, format);
    char *filename = zsys_vprintf (format, argptr);
    va_end (argptr);

    //  Try first to load secret certificate, which has both keys
    //  Then fallback to loading public certificate
    char filename_secret [256];
    snprintf (filename_secret, 256, "%s_secret", filename);
    zconfig_t *root = zconfig_load (filename_secret);
    if (!root)
        root = zconfig_load (filename);
        
    zcert_t *self = NULL;
    if (root) {
        char *public_text = zconfig_resolve (root, "/curve/public-key", NULL);
        char *secret_text = zconfig_resolve (root, "/curve/secret-key", NULL);
        if (public_text && strlen (public_text) == 40) {
            byte public_key [32] = { 0 };
            byte secret_key [32] = { 0 };
            zmq_z85_decode (public_key, public_text);
            if (secret_text && strlen (secret_text) == 40)
                zmq_z85_decode (secret_key, secret_text);

            //  Load metadata into certificate
            self = zcert_new_from (public_key, secret_key);
            zconfig_t *metadata = zconfig_locate (root, "/metadata");
            zconfig_t *item = metadata? zconfig_child (metadata): NULL;
            while (item) {
                zcert_set_meta (self, zconfig_name (item), zconfig_value (item));
                item = zconfig_next (item);
            }
        }
    }
    zconfig_destroy (&root);
    zstr_free (&filename);
    return self;
#else   
    return NULL;
#endif
}
Пример #4
0
zcert_t *
zcert_new (void)
{
    byte public_key [32] = { 0 };
    byte secret_key [32] = { 0 };

#if (ZMQ_VERSION_MAJOR == 4)
    if (zsys_has_curve ()) {
        char public_txt [41];
        char secret_txt [41];
        int rc = zmq_curve_keypair (public_txt, secret_txt);
        if (rc != 0)
            return NULL;
        zmq_z85_decode (public_key, public_txt);
        zmq_z85_decode (secret_key, secret_txt);
    }
#endif
    return zcert_new_from (public_key, secret_key);
}
Пример #5
0
zcert_t *
zcert_new (void)
{
    zcert_t *self = (zcert_t *) zmalloc (sizeof (zcert_t));
    assert (self);

    //  Initialize metadata, even if keys aren't working
    self->metadata = zhash_new ();
    zhash_autofree (self->metadata);
    
#if (ZMQ_VERSION_MAJOR == 4)
    int rc = zmq_curve_keypair (self->public_txt, self->secret_txt);
    assert (rc == 0);
    zmq_z85_decode (self->public_key, self->public_txt);
    zmq_z85_decode (self->secret_key, self->secret_txt);
#else
    strcpy (self->public_txt, "0000000000000000000000000000000000000000");
    strcpy (self->secret_txt, "0000000000000000000000000000000000000000");
#endif
    return self;
}
Пример #6
0
// Test vector: rfc.zeromq.org/spec:32/Z85
void test__zmq_z85_decode__valid__success ()
{
    static const size_t size = 10 * 4 / 5;
    static const uint8_t expected[size] = {0x86, 0x4F, 0xD2, 0x6F,
                                           0xB5, 0x59, 0xF7, 0x5B};
    static const char *encoded = "HelloWorld";
    uint8_t out_decoded[size] = {0};

    errno = 0;
    assert (zmq_z85_decode (out_decoded, encoded) != NULL);
    assert (zmq_errno () == 0);
    assert (memcmp (out_decoded, expected, size) == 0);
}
Пример #7
0
void test__zmq_z85_encode__zmq_z85_decode__roundtrip (
  const uint8_t (&test_data_)[SIZE])
{
    char test_data_z85[SIZE * 5 / 4 + 1];
    char *res1 = zmq_z85_encode (test_data_z85, test_data_, SIZE);
    assert (res1 != NULL);

    uint8_t test_data_decoded[SIZE];
    uint8_t *res2 = zmq_z85_decode (test_data_decoded, test_data_z85);
    assert (res2 != NULL);

    int res3 = memcmp (test_data_, test_data_decoded, SIZE);
    assert (res3 == 0);
}
Пример #8
0
void test__zmq_z85_decode__zmq_z85_encode__roundtrip (
  const char (&test_data_)[SIZE])
{
    const size_t decoded_size = (SIZE - 1) * 4 / 5;
    uint8_t test_data_decoded[decoded_size];
    uint8_t *res1 = zmq_z85_decode (test_data_decoded, test_data_);
    assert (res1 != NULL);

    char test_data_z85[SIZE];
    char *res2 =
      zmq_z85_encode (test_data_z85, test_data_decoded, decoded_size);
    assert (res2 != NULL);

    int res3 = memcmp (test_data_, test_data_z85, SIZE);
    assert (res3 == 0);
}
Пример #9
0
int main (void)
{
    void *context = zmq_ctx_new ();
    void *responder = zmq_socket (context, ZMQ_REP);
    int i=1;
    char skeystr[] = "JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6";
    uint8_t server_key [32];
    zmq_z85_decode (server_key, skeystr);
    zmq_setsockopt(responder, ZMQ_CURVE_SERVER, &i, sizeof(i));
    zmq_setsockopt(responder, ZMQ_CURVE_SECRETKEY, &server_key, sizeof(server_key));
    int rc = zmq_bind (responder, "tcp://*:55555");
    assert (rc == 0);

    while (1) {
        char buffer [10];
        zmq_recv (responder, buffer, 10, 0);
        printf ("Received Hello\n");
        sleep (1);
        zmq_send (responder, "World", 5, 0);
    }
    return 0;
}
Пример #10
0
JNIEXPORT jbyteArray JNICALL
Java_org_zeromq_ZMQ_00024Curve_z85Decode(JNIEnv *env, jclass cls, jstring key)
{
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4,0,0)
    const char *in_key = env->GetStringUTFChars (key, NULL);
    assert (in_key);

    uint8_t out_key [32];

    if (NULL == zmq_z85_decode (out_key, in_key)) {
        env->ReleaseStringUTFChars (key, in_key);
        return NULL;
    }

    env->ReleaseStringUTFChars (key, in_key);
    jbyteArray result = env->NewByteArray (32);
    env->SetByteArrayRegion (result, 0 , 32, reinterpret_cast<jbyte*>(out_key));

    return result;
#else
    raise_exception (env, ENOTSUP);
    return NULL;
#endif
}
Пример #11
0
int zmq::options_t::setsockopt (int option_, const void *optval_,
                                size_t optvallen_)
{
    bool is_int = (optvallen_ == sizeof (int));
    int value = is_int? *((int *) optval_): 0;
#if defined (ZMQ_ACT_MILITANT)
    bool malformed = true;          //  Did caller pass a bad option value?
#endif

    switch (option_) {
    case ZMQ_SNDHWM:
        if (is_int && value >= 0) {
            sndhwm = value;
            return 0;
        }
        break;

    case ZMQ_RCVHWM:
        if (is_int && value >= 0) {
            rcvhwm = value;
            return 0;
        }
        break;

    case ZMQ_AFFINITY:
        if (optvallen_ == sizeof (uint64_t)) {
            affinity = *((uint64_t*) optval_);
            return 0;
        }
        break;

    case ZMQ_IDENTITY:
        //  Identity is any binary string from 1 to 255 octets
        if (optvallen_ > 0 && optvallen_ < 256) {
            identity_size = optvallen_;
            memcpy (identity, optval_, identity_size);
            return 0;
        }
        break;

    case ZMQ_RATE:
        if (is_int && value > 0) {
            rate = value;
            return 0;
        }
        break;

    case ZMQ_RECOVERY_IVL:
        if (is_int && value >= 0) {
            recovery_ivl = value;
            return 0;
        }
        break;

    case ZMQ_SNDBUF:
        if (is_int && value >= 0) {
            sndbuf = value;
            return 0;
        }
        break;

    case ZMQ_RCVBUF:
        if (is_int && value >= 0) {
            rcvbuf = value;
            return 0;
        }
        break;

    case ZMQ_TOS:
        if (is_int && value >= 0) {
            tos = value;
            return 0;
        }
        break;

    case ZMQ_LINGER:
        if (is_int && value >= -1) {
            linger = value;
            return 0;
        }
        break;

    case ZMQ_RECONNECT_IVL:
        if (is_int && value >= -1) {
            reconnect_ivl = value;
            return 0;
        }
        break;

    case ZMQ_RECONNECT_IVL_MAX:
        if (is_int && value >= 0) {
            reconnect_ivl_max = value;
            return 0;
        }
        break;

    case ZMQ_BACKLOG:
        if (is_int && value >= 0) {
            backlog = value;
            return 0;
        }
        break;

    case ZMQ_MAXMSGSIZE:
        if (optvallen_ == sizeof (int64_t)) {
            maxmsgsize = *((int64_t *) optval_);
            return 0;
        }
        break;

    case ZMQ_MULTICAST_HOPS:
        if (is_int && value > 0) {
            multicast_hops = value;
            return 0;
        }
        break;

    case ZMQ_RCVTIMEO:
        if (is_int && value >= -1) {
            rcvtimeo = value;
            return 0;
        }
        break;

    case ZMQ_SNDTIMEO:
        if (is_int && value >= -1) {
            sndtimeo = value;
            return 0;
        }
        break;

    /*  Deprecated in favor of ZMQ_IPV6  */
    case ZMQ_IPV4ONLY:
        if (is_int && (value == 0 || value == 1)) {
            ipv6 = (value == 0);
            return 0;
        }
        break;

    /*  To replace the somewhat surprising IPV4ONLY */
    case ZMQ_IPV6:
        if (is_int && (value == 0 || value == 1)) {
            ipv6 = (value != 0);
            return 0;
        }
        break;

    case ZMQ_SOCKS_PROXY:
        if (optval_ == NULL && optvallen_ == 0) {
            socks_proxy_address.clear ();
            return 0;
        }
        else if (optval_ != NULL && optvallen_ > 0 ) {
            socks_proxy_address =
                std::string ((const char *) optval_, optvallen_);
            return 0;
        }
        break;

    case ZMQ_TCP_KEEPALIVE:
        if (is_int && (value == -1 || value == 0 || value == 1)) {
            tcp_keepalive = value;
            return 0;
        }
        break;

    case ZMQ_TCP_KEEPALIVE_CNT:
        if (is_int && (value == -1 || value >= 0)) {
            tcp_keepalive_cnt = value;
            return 0;
        }
        break;

    case ZMQ_TCP_KEEPALIVE_IDLE:
        if (is_int && (value == -1 || value >= 0)) {
            tcp_keepalive_idle = value;
            return 0;
        }
        break;

    case ZMQ_TCP_KEEPALIVE_INTVL:
        if (is_int && (value == -1 || value >= 0)) {
            tcp_keepalive_intvl = value;
            return 0;
        }
        break;

    case ZMQ_IMMEDIATE:
        if (is_int && (value == 0 || value == 1)) {
            immediate = value;
            return 0;
        }
        break;

    case ZMQ_TCP_ACCEPT_FILTER:
        if (optvallen_ == 0 && optval_ == NULL) {
            tcp_accept_filters.clear ();
            return 0;
        }
        else if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL && *((const char*) optval_) != 0) {
            std::string filter_str ((const char *) optval_, optvallen_);
            tcp_address_mask_t mask;
            int rc = mask.resolve (filter_str.c_str (), ipv6);
            if (rc == 0) {
                tcp_accept_filters.push_back (mask);
                return 0;
            }
        }
        break;

#       if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
    case ZMQ_IPC_FILTER_UID:
        if (optvallen_ == 0 && optval_ == NULL) {
            ipc_uid_accept_filters.clear ();
            return 0;
        }
        else if (optvallen_ == sizeof (uid_t) && optval_ != NULL) {
            ipc_uid_accept_filters.insert (*((uid_t *) optval_));
            return 0;
        }
        break;

    case ZMQ_IPC_FILTER_GID:
        if (optvallen_ == 0 && optval_ == NULL) {
            ipc_gid_accept_filters.clear ();
            return 0;
        }
        else if (optvallen_ == sizeof (gid_t) && optval_ != NULL) {
            ipc_gid_accept_filters.insert (*((gid_t *) optval_));
            return 0;
        }
        break;
#       endif

#       if defined ZMQ_HAVE_SO_PEERCRED
    case ZMQ_IPC_FILTER_PID:
        if (optvallen_ == 0 && optval_ == NULL) {
            ipc_pid_accept_filters.clear ();
            return 0;
        }
        else if (optvallen_ == sizeof (pid_t) && optval_ != NULL) {
            ipc_pid_accept_filters.insert (*((pid_t *) optval_));
            return 0;
        }
        break;
#       endif

    case ZMQ_PLAIN_SERVER:
        if (is_int && (value == 0 || value == 1)) {
            as_server = value;
            mechanism = value? ZMQ_PLAIN: ZMQ_NULL;
            return 0;
        }
        break;

    case ZMQ_PLAIN_USERNAME:
        if (optvallen_ == 0 && optval_ == NULL) {
            mechanism = ZMQ_NULL;
            return 0;
        }
        else if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
            plain_username.assign ((const char *) optval_, optvallen_);
            as_server = 0;
            mechanism = ZMQ_PLAIN;
            return 0;
        }
        break;

    case ZMQ_PLAIN_PASSWORD:
        if (optvallen_ == 0 && optval_ == NULL) {
            mechanism = ZMQ_NULL;
            return 0;
        }
        else if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
            plain_password.assign ((const char *) optval_, optvallen_);
            as_server = 0;
            mechanism = ZMQ_PLAIN;
            return 0;
        }
        break;

    case ZMQ_ZAP_DOMAIN:
        if (optvallen_ < 256) {
            zap_domain.assign ((const char *) optval_, optvallen_);
            return 0;
        }
        break;

        //  If libsodium isn't installed, these options provoke EINVAL
#       ifdef HAVE_LIBSODIUM
    case ZMQ_CURVE_SERVER:
        if (is_int && (value == 0 || value == 1)) {
            as_server = value;
            mechanism = value? ZMQ_CURVE: ZMQ_NULL;
            return 0;
        }
        break;

    case ZMQ_CURVE_PUBLICKEY:
        //  TODO: refactor repeated code for these three options
        //  into set_curve_key (destination, optval, optlen) method
        //  ==> set_curve_key (curve_public_key, optval_, optvallen_);
        if (optvallen_ == CURVE_KEYSIZE) {
            memcpy (curve_public_key, optval_, CURVE_KEYSIZE);
            mechanism = ZMQ_CURVE;
            return 0;
        }
        else if (optvallen_ == CURVE_KEYSIZE_Z85 + 1) {
            zmq_z85_decode (curve_public_key, (char *) optval_);
            mechanism = ZMQ_CURVE;
            return 0;
        }
        else
            //  Deprecated, not symmetrical with zmq_getsockopt
            if (optvallen_ == CURVE_KEYSIZE_Z85) {
                char z85_key [41];
                memcpy (z85_key, (char *) optval_, CURVE_KEYSIZE_Z85);
                z85_key [CURVE_KEYSIZE_Z85] = 0;
                zmq_z85_decode (curve_public_key, z85_key);
                mechanism = ZMQ_CURVE;
                return 0;
            }
        break;

    case ZMQ_CURVE_SECRETKEY:
        if (optvallen_ == CURVE_KEYSIZE) {
            memcpy (curve_secret_key, optval_, CURVE_KEYSIZE);
            mechanism = ZMQ_CURVE;
            return 0;
        }
        else if (optvallen_ == CURVE_KEYSIZE_Z85 + 1) {
            zmq_z85_decode (curve_secret_key, (char *) optval_);
            mechanism = ZMQ_CURVE;
            return 0;
        }
        else
            //  Deprecated, not symmetrical with zmq_getsockopt
            if (optvallen_ == CURVE_KEYSIZE_Z85) {
                char z85_key [41];
                memcpy (z85_key, (char *) optval_, CURVE_KEYSIZE_Z85);
                z85_key [CURVE_KEYSIZE_Z85] = 0;
                zmq_z85_decode (curve_secret_key, z85_key);
                mechanism = ZMQ_CURVE;
                return 0;
            }
        break;

    case ZMQ_CURVE_SERVERKEY:
        if (optvallen_ == CURVE_KEYSIZE) {
            memcpy (curve_server_key, optval_, CURVE_KEYSIZE);
            mechanism = ZMQ_CURVE;
            as_server = 0;
            return 0;
        }
        else if (optvallen_ == CURVE_KEYSIZE_Z85 + 1) {
            zmq_z85_decode (curve_server_key, (char *) optval_);
            mechanism = ZMQ_CURVE;
            as_server = 0;
            return 0;
        }
        else
            //  Deprecated, not symmetrical with zmq_getsockopt
            if (optvallen_ == CURVE_KEYSIZE_Z85) {
                char z85_key [41];
                memcpy (z85_key, (char *) optval_, CURVE_KEYSIZE_Z85);
                z85_key [CURVE_KEYSIZE_Z85] = 0;
                zmq_z85_decode (curve_server_key, z85_key);
                mechanism = ZMQ_CURVE;
                as_server = 0;
                return 0;
            }
        break;
#       endif

    case ZMQ_CONFLATE:
        if (is_int && (value == 0 || value == 1)) {
            conflate = (value != 0);
            return 0;
        }
        break;

        //  If libgssapi isn't installed, these options provoke EINVAL
#       ifdef HAVE_LIBGSSAPI_KRB5
    case ZMQ_GSSAPI_SERVER:
        if (is_int && (value == 0 || value == 1)) {
            as_server = value;
            mechanism = ZMQ_GSSAPI;
            return 0;
        }
        break;

    case ZMQ_GSSAPI_PRINCIPAL:
        if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
            gss_principal.assign ((const char *) optval_, optvallen_);
            mechanism = ZMQ_GSSAPI;
            return 0;
        }
        break;

    case ZMQ_GSSAPI_SERVICE_PRINCIPAL:
        if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
            gss_service_principal.assign ((const char *) optval_, optvallen_);
            mechanism = ZMQ_GSSAPI;
            as_server = 0;
            return 0;
        }
        break;

    case ZMQ_GSSAPI_PLAINTEXT:
        if (is_int && (value == 0 || value == 1)) {
            gss_plaintext = (value != 0);
            return 0;
        }
        break;
#       endif

    case ZMQ_HANDSHAKE_IVL:
        if (is_int && value >= 0) {
            handshake_ivl = value;
            return 0;
        }
        break;

    default:
#if defined (ZMQ_ACT_MILITANT)
        //  There are valid scenarios for probing with unknown socket option
        //  values, e.g. to check if security is enabled or not. This will not
        //  provoke a militant assert. However, passing bad values to a valid
        //  socket option will, if ZMQ_ACT_MILITANT is defined.
        malformed = false;
#endif
        break;
    }
#if defined (ZMQ_ACT_MILITANT)
    //  There is no valid use case for passing an error back to the application
    //  when it sent malformed arguments to a socket option. Use ./configure
    //  --with-militant to enable this checking.
    if (malformed)
        zmq_assert (false);
#endif
    errno = EINVAL;
    return -1;
}
Пример #12
0
int zmq::options_t::setsockopt (int option_, const void *optval_,
    size_t optvallen_)
{
    bool is_int = (optvallen_ == sizeof (int));
    int value = is_int? *((int *) optval_): 0;

    switch (option_) {
        case ZMQ_SNDHWM:
            if (is_int && value >= 0) {
                sndhwm = value;
                return 0;
            }
            break;

        case ZMQ_RCVHWM:
            if (is_int && value >= 0) {
                rcvhwm = value;
                return 0;
            }
            break;

        case ZMQ_AFFINITY:
            if (optvallen_ == sizeof (uint64_t)) {
                affinity = *((uint64_t*) optval_);
                return 0;
            }
            break;

        case ZMQ_IDENTITY:
            //  Empty identity is invalid as well as identity longer than
            //  255 bytes. Identity starting with binary zero is invalid
            //  as these are used for auto-generated identities.
            if (optvallen_ > 0 && optvallen_ < 256
            && *((const unsigned char *) optval_) != 0) {
                identity_size = optvallen_;
                memcpy (identity, optval_, identity_size);
                return 0;
            }
            break;

        case ZMQ_RATE:
            if (is_int && value > 0) {
                rate = value;
                return 0;
            }
            break;

        case ZMQ_RECOVERY_IVL:
            if (is_int && value >= 0) {
                recovery_ivl = value;
                return 0;
            }
            break;

        case ZMQ_SNDBUF:
            if (is_int && value >= 0) {
                sndbuf = value;
                return 0;
            }
            break;

        case ZMQ_RCVBUF:
            if (is_int && value >= 0) {
                rcvbuf = value;
                return 0;
            }
            break;

        case ZMQ_TOS:
            if (is_int && value >= 0) {
                tos = value;
                return 0;
            }
            break;

        case ZMQ_LINGER:
            if (is_int && value >= -1) {
                linger = value;
                return 0;
            }
            break;

        case ZMQ_RECONNECT_IVL:
            if (is_int && value >= -1) {
                reconnect_ivl = value;
                return 0;
            }
            break;

        case ZMQ_RECONNECT_IVL_MAX:
            if (is_int && value >= 0) {
                reconnect_ivl_max = value;
                return 0;
            }
            break;

        case ZMQ_BACKLOG:
            if (is_int && value >= 0) {
                backlog = value;
                return 0;
            }
            break;

        case ZMQ_MAXMSGSIZE:
            if (optvallen_ == sizeof (int64_t)) {
                maxmsgsize = *((int64_t *) optval_);
                return 0;
            }
            break;

        case ZMQ_MULTICAST_HOPS:
            if (is_int && value > 0) {
                multicast_hops = value;
                return 0;
            }
            break;

        case ZMQ_RCVTIMEO:
            if (is_int && value >= -1) {
                rcvtimeo = value;
                return 0;
            }
            break;

        case ZMQ_SNDTIMEO:
            if (is_int && value >= -1) {
                sndtimeo = value;
                return 0;
            }
            break;

        /*  Deprecated in favor of ZMQ_IPV6  */
        case ZMQ_IPV4ONLY:
            if (is_int && (value == 0 || value == 1)) {
                ipv6 = (value == 0);
                return 0;
            }
            break;

        /*  To replace the somewhat surprising IPV4ONLY */
        case ZMQ_IPV6:
            if (is_int && (value == 0 || value == 1)) {
                ipv6 = (value != 0);
                return 0;
            }
            break;

        case ZMQ_TCP_KEEPALIVE:
            if (is_int && (value >= -1 || value <= 1)) {
                tcp_keepalive = value;
                return 0;
            }
            break;

        case ZMQ_TCP_KEEPALIVE_CNT:
            if (is_int && (value == -1 || value >= 0)) {
                tcp_keepalive_cnt = value;
                return 0;
            }
            break;

        case ZMQ_TCP_KEEPALIVE_IDLE:
            if (is_int && (value == -1 || value >= 0)) {
                tcp_keepalive_idle = value;
                return 0;
            }
            break;

        case ZMQ_TCP_KEEPALIVE_INTVL:
            if (is_int && (value == -1 || value >= 0)) {
                tcp_keepalive_intvl = value;
                return 0;
            }
            break;

        case ZMQ_IMMEDIATE:
            if (is_int && (value == 0 || value == 1)) {
                immediate = value;
                return 0;
            }
            break;

        case ZMQ_TCP_ACCEPT_FILTER:
            if (optvallen_ == 0 && optval_ == NULL) {
                tcp_accept_filters.clear ();
                return 0;
            }
            else
            if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL && *((const char*) optval_) != 0) {
                std::string filter_str ((const char *) optval_, optvallen_);
                tcp_address_mask_t mask;
                int rc = mask.resolve (filter_str.c_str (), ipv6);
                if (rc == 0) {
                    tcp_accept_filters.push_back (mask);
                    return 0;
                }
            }
            break;

#       if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
        case ZMQ_ZAP_IPC_CREDS:
            if (is_int && (value == 0 || value == 1)) {
                zap_ipc_creds = (value != 0);
                return 0;
            }
            break;

        case ZMQ_IPC_FILTER_UID:
            if (optvallen_ == 0 && optval_ == NULL) {
                ipc_uid_accept_filters.clear ();
                return 0;
            }
            else
            if (optvallen_ == sizeof (uid_t) && optval_ != NULL) {
                ipc_uid_accept_filters.insert (*((uid_t *) optval_));
                return 0;
            }
            break;

        case ZMQ_IPC_FILTER_GID:
            if (optvallen_ == 0 && optval_ == NULL) {
                ipc_gid_accept_filters.clear ();
                return 0;
            }
            else
            if (optvallen_ == sizeof (gid_t) && optval_ != NULL) {
                ipc_gid_accept_filters.insert (*((gid_t *) optval_));
                return 0;
            }
            break;
#       endif

#       if defined ZMQ_HAVE_SO_PEERCRED
        case ZMQ_IPC_FILTER_PID:
            if (optvallen_ == 0 && optval_ == NULL) {
                ipc_pid_accept_filters.clear ();
                return 0;
            }
            else
            if (optvallen_ == sizeof (pid_t) && optval_ != NULL) {
                ipc_pid_accept_filters.insert (*((pid_t *) optval_));
                return 0;
            }
            break;
#       endif

        case ZMQ_PLAIN_SERVER:
            if (is_int && (value == 0 || value == 1)) {
                as_server = value;
                mechanism = value? ZMQ_PLAIN: ZMQ_NULL;
                return 0;
            }
            break;

        case ZMQ_PLAIN_USERNAME:
            if (optvallen_ == 0 && optval_ == NULL) {
                mechanism = ZMQ_NULL;
                return 0;
            }
            else
            if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
                plain_username.assign ((const char *) optval_, optvallen_);
                as_server = 0;
                mechanism = ZMQ_PLAIN;
                return 0;
            }
            break;

        case ZMQ_PLAIN_PASSWORD:
            if (optvallen_ == 0 && optval_ == NULL) {
                mechanism = ZMQ_NULL;
                return 0;
            }
            else
            if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
                plain_password.assign ((const char *) optval_, optvallen_);
                as_server = 0;
                mechanism = ZMQ_PLAIN;
                return 0;
            }
            break;

        case ZMQ_ZAP_DOMAIN:
            if (optvallen_ < 256) {
                zap_domain.assign ((const char *) optval_, optvallen_);
                return 0;
            }
            break;

        //  If libsodium isn't installed, these options provoke EINVAL
#       ifdef HAVE_LIBSODIUM
        case ZMQ_CURVE_SERVER:
            if (is_int && (value == 0 || value == 1)) {
                as_server = value;
                mechanism = value? ZMQ_CURVE: ZMQ_NULL;
                return 0;
            }
            break;

        case ZMQ_CURVE_PUBLICKEY:
            if (optvallen_ == CURVE_KEYSIZE) {
                memcpy (curve_public_key, optval_, CURVE_KEYSIZE);
                mechanism = ZMQ_CURVE;
                return 0;
            }
            else
            if (optvallen_ == CURVE_KEYSIZE_Z85) {
                zmq_z85_decode (curve_public_key, (char *) optval_);
                mechanism = ZMQ_CURVE;
                return 0;
            }
            break;

        case ZMQ_CURVE_SECRETKEY:
            if (optvallen_ == CURVE_KEYSIZE) {
                memcpy (curve_secret_key, optval_, CURVE_KEYSIZE);
                mechanism = ZMQ_CURVE;
                return 0;
            }
            else
            if (optvallen_ == CURVE_KEYSIZE_Z85) {
                zmq_z85_decode (curve_secret_key, (char *) optval_);
                mechanism = ZMQ_CURVE;
                return 0;
            }
            break;

        case ZMQ_CURVE_SERVERKEY:
            if (optvallen_ == CURVE_KEYSIZE) {
                memcpy (curve_server_key, optval_, CURVE_KEYSIZE);
                as_server = 0;
                mechanism = ZMQ_CURVE;
                return 0;
            }
            else
            if (optvallen_ == CURVE_KEYSIZE_Z85) {
                zmq_z85_decode (curve_server_key, (char *) optval_);
                as_server = 0;
                mechanism = ZMQ_CURVE;
                return 0;
            }
            break;
#       endif

        case ZMQ_CONFLATE:
            if (is_int && (value == 0 || value == 1)) {
                conflate = (value != 0);
                return 0;
            }
            break;

        default:
            break;
    }
    errno = EINVAL;
    return -1;
}