Exemplo n.º 1
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static void
wrap_zmq_init(zmq_drv_t *drv, const uint8_t* bytes, size_t size)
{
    int io_threads  = *bytes;

    assert(sizeof(uint8_t) == size);

    zmqdrv_fprintf("init (io_threads: %d)\r\n", io_threads);

    // We only support a single zmq context, but zeromq itself supports multiple
    if (drv->zmq_context)
    {
        reply_error(drv->port, driver_caller(drv->port), EBUSY);
        return;
    }

    drv->terminating = false;
    drv->zmq_context = zmq_init(io_threads);

    if (!drv->zmq_context)
    {
        reply_error(drv->port, driver_caller(drv->port), zmq_errno());
        return;
    }

    zmqdrv_fprintf("init %p\r\n", drv->zmq_context);

    reply_ok(drv->port, driver_caller(drv->port));
}
Exemplo n.º 2
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static void
zmqdrv_process_exit(ErlDrvData handle, ErlDrvMonitor* monitor)
{
    zmq_drv_t*     drv = reinterpret_cast<zmq_drv_t*>(handle);
    ErlDrvTermData pid = driver_get_monitored_process(drv->port, monitor);

    zmqdrv_fprintf("detected death of %lu process\r\n", pid);

    zmq_sock_info* si = drv->get_socket_info(pid);

    assert(NULL != si);

    zmqdrv_fprintf("force close %p\r\n", si->socket);

    driver_demonitor_process(drv->port, &si->monitor);

    if (si->busy)
    {
        // Remove socket from vm polling
        driver_select(drv->port, si->fd, ERL_DRV_READ, 0);
    }

    drv->zmq_pid_socket.erase(pid);
    drv->zmq_fd_socket.erase(si->fd);

    //zmq_close(Socket) is called in ~zmq_sock_info
    delete si;
}
Exemplo n.º 3
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static void
wrap_zmq_socket(zmq_drv_t *drv, const uint8_t* bytes, size_t size)
{
    int type = *bytes;

    assert(sizeof(uint8_t) == size);

    zmqdrv_fprintf("socket (type: %d)\r\n", type);

    ErlDrvTermData caller = driver_caller(drv->port);

    if (drv->terminating)
    {
        reply_error(drv->port, caller, ETERM);
        return;
    }

    assert(NULL == drv->get_socket_info(caller));

    // Runtime validation as well in case zmq_drv.erl is used directly rather
    // than through zmq_socket.erl gen_server.
    if (NULL != drv->get_socket_info(caller))
    {
        reply_error(drv->port, caller, EBUSY);
        return;
    }

    void* s = zmq_socket(drv->zmq_context, type);

    if (!s)
    {
        reply_error(drv->port, caller, zmq_errno());
        return;
    }

    //TODO: Support Windows 'SOCKET' type?
    int fd; size_t fd_size = sizeof(fd);
    if (0 != zmq_getsockopt(s, ZMQ_FD, &fd, &fd_size))
    {
        reply_error(drv->port, caller, zmq_errno());
        zmq_close(s);
        return;
    }

    zmq_sock_info* si = new zmq_sock_info(s, (ErlDrvEvent)fd);

    if (!si)
    {
        driver_failure_posix(drv->port, ENOMEM);
        return;
    }

    driver_monitor_process(drv->port, caller, &si->monitor);
    drv->zmq_pid_socket[caller] = si;
    drv->zmq_fd_socket[si->fd] = si;

    zmqdrv_fprintf("socket %p owner %lu\r\n", si->socket, caller);

    reply_ok(drv->port, caller);
}
Exemplo n.º 4
0
zmq_drv_t::~zmq_drv_t()
{
    for (zmq_pid_sockets_map_t::iterator it = zmq_pid_sockets.begin();
            it != zmq_pid_sockets.end(); ++it)
        driver_demonitor_process(port, &it->second.monitor);

    for (zmq_fd_sockets_map_t::iterator it = zmq_fd_sockets.begin();
            it != zmq_fd_sockets.end(); ++it)
        driver_select(port, (ErlDrvEvent)it->first, ERL_DRV_READ, 0);

    for (zmq_sock_info *it=zmq_sock_infos, *next=(it ? it->next : NULL); it; it = next) {
        next = it->next;
        delete (&*it);
    }
    zmq_sockets.clear();
    zmq_idxs.clear();
    zmq_pid_sockets.clear();
    zmq_fd_sockets.clear();

    if (zmq_context) {
        zmqdrv_fprintf("calling zmq_term(context) ...\r\n");
        zmq_term(zmq_context);
        zmqdrv_fprintf("terminated zmq context\r\n");
    }
}
Exemplo n.º 5
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static void
zmqdrv_stop(ErlDrvData handle)
{
    zmqdrv_fprintf("zmq port driver stopping\r\n");
    delete reinterpret_cast<zmq_drv_t*>(handle);
    zmqdrv_fprintf("zmq port driver stopped\r\n");
}
Exemplo n.º 6
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static void
wrap_zmq_recv(zmq_drv_t *drv, const uint8_t* bytes, size_t size)
{
    int flags = *bytes;

    assert(sizeof(uint8_t) == size);

    ErlDrvTermData caller = driver_caller(drv->port);

    if (drv->terminating)
    {
        reply_error(drv->port, caller, ETERM);
        return;
    }

    zmq_sock_info* si = drv->get_socket_info(caller);

    if (!si)
    {
        reply_error(drv->port, caller, ENODEV);
        return;
    }

    assert(0 == si->in_caller);

    zmqdrv_fprintf("recv %p (flags: %d)\r\n", si->socket, flags);

    zmq_msg_t msg;
    zmq_msg_init(&msg);

    if (0 == zmq_recv(si->socket, &msg, flags|ZMQ_NOBLOCK))
    {
        reply_ok_binary(drv->port, caller, zmq_msg_data(&msg), zmq_msg_size(&msg));
    }
    else if (ZMQ_NOBLOCK != (ZMQ_NOBLOCK & flags) && EAGAIN == zmq_errno())
    {
        // Caller requested blocking recv
        // No input available. Make the caller wait by not returning result
        zmqdrv_fprintf("recv %p blocking\r\n", si->socket);

        si->in_flags = flags;
        si->in_caller = caller;

        if (!si->busy)
        {
            driver_select(drv->port, si->fd, ERL_DRV_READ, 1);
            si->busy = true;
        }
    }
    else
    {
        reply_error(drv->port, caller, zmq_errno());
    }

    zmq_msg_close(&msg);
}
Exemplo n.º 7
0
static void 
zmqdrv_setsockopt(zmq_drv_t *drv, ErlIOVec *ev)
{
    ErlDrvBinary*  bin   = ev->binv[1];
    char*          bytes = bin->orig_bytes;
    uint32_t       idx   = ntohl(*(uint32_t*)(bytes+1));
    zmq_sock_info* si    = drv->get_socket_info(idx);
    uint8_t        n     = *(uint8_t*)(bytes+sizeof(idx)+1);
    char*          p     = bytes + 1 + sizeof(idx) + 1;

    if (idx > drv->zmq_socket_count || !si) {
        zmqdrv_error_code(drv, ENODEV);
        return;
    }

    zmqdrv_fprintf("setsockopt %p (setting %d options)\r\n", si->socket, (int)n);

    for (uint8_t j=0; j < n; ++j) {
        unsigned char option = *p++;
        uint64_t optvallen   = *p++;
        void*    optval      = p;

        switch (option) {
            case ZMQ_HWM:           assert(optvallen == 8);  break;
            case ZMQ_SWAP:          assert(optvallen == 8);  break;
            case ZMQ_AFFINITY:      assert(optvallen == 8);  break;
            case ZMQ_IDENTITY:      assert(optvallen < 256); break;
            case ZMQ_SUBSCRIBE:     assert(optvallen < 256); break;
            case ZMQ_UNSUBSCRIBE:   assert(optvallen < 256); break;
            case ZMQ_RATE:          assert(optvallen == 8);  break;
            case ZMQ_RECOVERY_IVL:  assert(optvallen == 8);  break;
            case ZMQ_MCAST_LOOP:    assert(optvallen == 8);  break;
            case ZMQ_SNDBUF:        assert(optvallen == 8);  break;
            case ZMQ_RCVBUF:        assert(optvallen == 8);  break;
            case ZMQ_ACTIVE:        assert(optvallen == 1);  break;
        }

        zmqdrv_fprintf("setsockopt %p (%d)\r\n", si->socket, option);

        if (option == ZMQ_ACTIVE)
            si->active_mode = *(char*)optval;
        else if (zmq_setsockopt(si->socket, option, optval, optvallen) < 0) {
            zmqdrv_error_code(drv, zmq_errno());
            return;
        }

        p += optvallen;
    }

    zmqdrv_ok(drv);
}
Exemplo n.º 8
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static void
wrap_zmq_close(zmq_drv_t *drv)
{
    ErlDrvTermData caller = driver_caller(drv->port);
    zmq_sock_info* si = drv->get_socket_info(caller);

    if (!si)
    {
        reply_error(drv->port, caller, ENODEV);
        return;
    }

    zmqdrv_fprintf("close %p\r\n", si->socket);

    driver_demonitor_process(drv->port, &si->monitor);

    if (si->busy)
    {
        // Remove socket from vm polling
        driver_select(drv->port, si->fd, ERL_DRV_READ, 0);
    }

    drv->zmq_pid_socket.erase(caller);
    drv->zmq_fd_socket.erase(si->fd);

    //zmq_close(Socket) is called in ~zmq_sock_info
    delete si;

    reply_ok(drv->port, caller);
}
Exemplo n.º 9
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static void
wrap_zmq_connect(zmq_drv_t *drv, const uint8_t* bytes, size_t size)
{
    // expects the endpoint to be zero terminated
    char* endpoint  = (char*)bytes;

    // TODO: check for zero termination within size limit
    assert(sizeof(char) <= size); // Must always have at least the 0 terminating char.

    ErlDrvTermData caller = driver_caller(drv->port);

    if (drv->terminating)
    {
        reply_error(drv->port, caller, ETERM);
        return;
    }

    zmq_sock_info* si = drv->get_socket_info(caller);

    if (!si)
    {
        reply_error(drv->port, caller, ENODEV);
        return;
    }

    zmqdrv_fprintf("connect %p (endpoint: %s)\r\n", si->socket, endpoint);

    if (0 != zmq_connect(si->socket, endpoint))
    {
        reply_error(drv->port, caller, zmq_errno());
        return;
    }

    reply_ok(drv->port, caller);
}
Exemplo n.º 10
0
int zmq_drv_t::del_socket(uint32_t idx)
{
    zmq_sock_info* s;
    int ret = -1;

    zmq_idx_socket_map_t::iterator it = zmq_sockets.find(idx);
    if (it == zmq_sockets.end()) {
        zmqdrv_fprintf("warning: socket info not found for idx %d\r\n", idx);
        return ret;
    }

    s = it->second;
    s->unlink();
    if (s == zmq_sock_infos)
        zmq_sock_infos = s->next;

    zmq_sockets.erase(idx);
    zmq_idxs.erase(s->socket);

    {
        // Remove the socket from a list of sockets owned by pid.
        // If this was the last socket, demonitor pid.
        zmq_pid_sockets_map_t::iterator it = zmq_pid_sockets.find(s->owner);
        if (it != zmq_pid_sockets.end()) {
            it->second.sockets.erase(s);
            if (it->second.sockets.empty()) {
                driver_demonitor_process(port, &it->second.monitor);
                zmq_pid_sockets.erase(it);
            }
        }
    }
    {
        zmq_fd_sockets_map_t::iterator it = zmq_fd_sockets.find(s->fd);
        if (it != zmq_fd_sockets.end()) {
            it->second.erase(s);
            if (it->second.empty()) {
                zmq_fd_sockets.erase(it->first);
                driver_select(port, (ErlDrvEvent)it->first, ERL_DRV_READ, 0);
                zmqdrv_fprintf("unregistered sig_fd(%d) with VM\r\n", it->first);
            }
        }
    }

    delete s;
    return 0;
}
Exemplo n.º 11
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static void
wrap_zmq_term(zmq_drv_t *drv)
{
    zmqdrv_fprintf("term %p\r\n", drv->zmq_context);

    if (0 < drv->zmq_pid_socket.size())
    {
        for (zmq_pid_socket_map_t::iterator it = drv->zmq_pid_socket.begin(); it != drv->zmq_pid_socket.end(); ++it)
        {
            zmq_sock_info* si = it->second;

            if (si->busy)
            {
                // Remove socket from erlang vm polling
                driver_select(drv->port, si->fd, ERL_DRV_READ, 0);

                if (si->out_caller)
                {
                    reply_error(drv->port, si->out_caller, ETERM);
                    si->out_caller = 0;
                    zmq_msg_close(&si->out_msg);
                }
                if (si->in_caller)
                {
                    reply_error(drv->port, si->in_caller, ETERM);
                    si->in_caller = 0;
                }
                if (si->poll_caller)
                {
                    send_events(drv->port, si->poll_caller, (uint32_t)ZMQ_POLLERR);
                    si->poll_caller = 0;
                }

                si->busy = false;
            }
        }

        // TODO: Remove if zeromq itself ever gets fixed. As zmq_term() is a
        // blocking call, and will not return until all sockets are closed,
        // so do not allow it to be called while there are open sockets.
        drv->terminating = true;
        reply_error(drv->port, driver_caller(drv->port), EAGAIN);
        return;
    }

    // cross fingers and hope zmq_term() doesn't block, else we hardlock.
    if (0 != zmq_term(drv->zmq_context))
    {
        reply_error(drv->port, driver_caller(drv->port), zmq_errno());
        return;
    }

    drv->zmq_context = NULL;

    reply_ok(drv->port, driver_caller(drv->port));
}
Exemplo n.º 12
0
static void
zmqdrv_term(zmq_drv_t *drv, ErlIOVec *ev)
{
    if (!drv->zmq_context) {
        zmqdrv_error_code(drv, ENODEV);
        return;
    }

    zmqdrv_fprintf("calling zmq_term(context) ...\r\n");
    int rc = zmq_term(drv->zmq_context);
    zmqdrv_fprintf("terminated zmq context\r\n");

    if (rc < 0) {
        zmqdrv_error_code(drv, zmq_errno());
        return;
    }

    zmqdrv_ok(drv);
    drv->zmq_context = NULL;
}
Exemplo n.º 13
0
static void
zmqdrv_send(zmq_drv_t *drv, ErlIOVec *ev)
{
    ErlDrvBinary*  bin   = ev->binv[1];
    char*          bytes = bin->orig_bytes;
    uint32_t       idx   = ntohl(*(uint32_t*)(bytes+1));
    zmq_sock_info* si    = drv->get_socket_info(idx);
    uint32_t       flags = ntohl(*(uint32_t*)(bytes+5));
    void*          data  = (void *)(bytes + 9);
    size_t         size  = bin->orig_size - 9;

    if (idx > drv->zmq_socket_count || !si) {
        zmqdrv_error_code(drv, ENODEV);
        return;
    }

#ifdef ZMQDRV_DEBUG
    uint32_t events;
    size_t events_size = sizeof(events);
    zmq_getsockopt(si->socket, ZMQ_EVENTS, &events, &events_size);
    zmqdrv_fprintf("sending %p [idx=%d] %lu bytes (events=%d)\r\n", si->socket, idx, size, events);
#endif

    if (si->out_caller != 0) {
        // There's still an unwritten message pending
        zmqdrv_error_code(drv, EBUSY);
        return;
    }

    // Increment the reference count on binary so that zmq can
    // take ownership of it.
    driver_binary_inc_refc(bin);

    if (zmq_msg_init_data(&si->out_msg, data, size, &zmq_free_binary, bin)) {
        zmqdrv_error_code(drv, zmq_errno());
        driver_binary_dec_refc(bin);
        return;
    }

    if (zmq_send(si->socket, &si->out_msg, flags | ZMQ_NOBLOCK) == 0) {
        zmqdrv_ok(drv);
        zmqdrv_ready_input((ErlDrvData)drv, (ErlDrvEvent)si->fd);
    } else {
        int e = zmq_errno();
        if (e == EAGAIN) {
            // No msg returned to caller - make him wait until async
            // send succeeds
            si->out_caller = driver_caller(drv->port);
            return;
        }
        zmqdrv_error_code(drv, e);
    }
    zmq_msg_close(&si->out_msg);
}
Exemplo n.º 14
0
// Called when an Erlang process owning sockets died.
// Perform cleanup of orphan sockets owned by pid.
static void 
zmqdrv_process_exit(ErlDrvData handle, ErlDrvMonitor* monitor)
{
    zmq_drv_t*     drv = (zmq_drv_t *)handle;
    ErlDrvTermData pid = driver_get_monitored_process(drv->port, monitor);

    zmqdrv_fprintf("detected death of %lu process\r\n", pid);

    driver_demonitor_process(drv->port, monitor);

    // Walk through the list of sockets and close the ones
    // owned by pid.
    zmq_pid_sockets_map_t::iterator it=drv->zmq_pid_sockets.find(pid);

    if (it != drv->zmq_pid_sockets.end()) {
        zmqdrv_fprintf("pid %lu has %lu sockets to be closed\r\n", pid, it->second.sockets.size());
        for(zmq_sock_set_t::iterator sit = it->second.sockets.begin();
            sit != it->second.sockets.end(); ++sit)
            drv->del_socket((*sit)->idx);
    }
}
Exemplo n.º 15
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static void
zmqdrv_outputv(ErlDrvData handle, ErlIOVec *ev)
{
    zmq_drv_t*            drv   = reinterpret_cast<zmq_drv_t*>(handle);
    ErlDrvBinary*         bin   = ev->binv[1];
    enum driver_commands  cmd   = (enum driver_commands)bin->orig_bytes[0];
    uint8_t*              bytes = (uint8_t*)&bin->orig_bytes[1];

    assert(1 <= bin->orig_size);

    zmqdrv_fprintf("driver got command %d on thread %p\r\n", (int)cmd, erl_drv_thread_self());

    switch (cmd)
    {
        case ZMQ_INIT:
            wrap_zmq_init(drv, bytes, bin->orig_size - 1);
            break;
        case ZMQ_TERM:
            wrap_zmq_term(drv);
            break;
        case ZMQ_SOCKET:
            wrap_zmq_socket(drv, bytes, bin->orig_size - 1);
            break;
        case ZMQ_CLOSE:
            wrap_zmq_close(drv);
            break;
        case ZMQ_SETSOCKOPT:
            wrap_zmq_setsockopt(drv, bytes, bin->orig_size - 1);
            break;
        case ZMQ_GETSOCKOPT:
            wrap_zmq_getsockopt(drv, bytes, bin->orig_size - 1);
            break;
        case ZMQ_BIND:
            wrap_zmq_bind(drv, bytes, bin->orig_size - 1);
            break;
        case ZMQ_CONNECT:
            wrap_zmq_connect(drv, bytes, bin->orig_size - 1);
            break;
        case ZMQ_SEND:
            wrap_zmq_send(drv, bytes, bin->orig_size - 1, bin);
            break;
        case ZMQ_RECV:
            wrap_zmq_recv(drv, bytes, bin->orig_size - 1);
            break;
        case ZMQ_POLL:
            wrap_zmq_poll(drv, bytes, bin->orig_size - 1);
            break;
        default :
            assert(true);
    }
}
Exemplo n.º 16
0
/* Erlang command, called on binary input from VM. */
static void
zmqdrv_outputv(ErlDrvData handle, ErlIOVec *ev)
{
    zmq_drv_t*    drv  = (zmq_drv_t *)handle;
    ErlDrvBinary* data = ev->binv[1];
    unsigned char cmd  = data->orig_bytes[0]; // First byte is the command

    zmqdrv_fprintf("driver got command %d on thread %p\r\n", (int)cmd, erl_drv_thread_self());

    switch (cmd) {
        case ZMQ_INIT :
            zmqdrv_init(drv, ev);
            break;
        case ZMQ_TERM :
            zmqdrv_term(drv, ev);
            break;
        case ZMQ_SOCKET :
            zmqdrv_socket(drv, ev);
            break;
        case ZMQ_CLOSE :
            zmqdrv_close(drv, ev);
            break;
        case ZMQ_SETSOCKOPT :
            zmqdrv_setsockopt(drv, ev);
            break;
        case ZMQ_GETSOCKOPT :
            zmqdrv_getsockopt(drv, ev);
            break;
        case ZMQ_BIND :
            zmqdrv_bind(drv, ev);
            break;
        case ZMQ_CONNECT :
            zmqdrv_connect(drv, ev);
            break;
        case ZMQ_SEND :
            zmqdrv_send(drv, ev);
            break;
        case ZMQ_RECV :
            zmqdrv_recv(drv, ev);
            break;
        default :
            zmqdrv_error(drv, "Invalid driver command");
    }
}
Exemplo n.º 17
0
static void
zmqdrv_socket(zmq_drv_t *drv, ErlIOVec *ev)
{
    ErlDrvBinary* bin   = ev->binv[1];
    char*         bytes = bin->orig_bytes;
    int           type  = *(bytes + 1);

    void* s = zmq_socket(drv->zmq_context, type);
    if (!s) {
        zmqdrv_error_code(drv, zmq_errno());
        return;
    }

    int sig_fd;
    size_t sig_size = sizeof(sig_fd);
    zmq_getsockopt(s, ZMQ_FD, &sig_fd, &sig_size);

    if (sig_fd < 0) {
        zmqdrv_error(drv, "Invalid signaler");
        return;
    }

    // Register a new socket handle in order to avoid
    // passing actual address of socket to Erlang.  This
    // way it's more safe and also portable between 32 and
    // 64 bit OS's.
    uint32_t n = ++drv->zmq_socket_count;

    zmq_sock_info* zsi = new zmq_sock_info(s, n, driver_caller(drv->port), sig_fd);
    if (!zsi) {
        driver_failure_posix(drv->port, ENOMEM);
        return;
    }

    drv->add_socket(zsi);

    zmqdrv_fprintf("socket %p [idx=%d] owner=%ld\r\n", s, n, zsi->owner);

    ErlDrvTermData spec[] = {ERL_DRV_ATOM,  am_zok,
                             ERL_DRV_UINT,  n,
                             ERL_DRV_TUPLE, 2};
    driver_send_term(drv->port, zsi->owner, spec, sizeof(spec)/sizeof(spec[0]));
}
Exemplo n.º 18
0
static void
zmqdrv_init(zmq_drv_t *drv, ErlIOVec *ev)
{
    /* 
     * FIXME 
     * Use ei_decode_* to decode input from erlang VM.
     * This stuff is not documented anywhere, for now 
     * binary ErlIOVec is decoded by poking in iov struct.
     * 
     * Serge: Dhammika, ei_decode can only be used to decode
     * external binary format in the "output" callback function.
     * It's not suitable for using inside "outputv" body that
     * operates on I/O vectors unless you use term_to_binary/1
     * call to explicitely convert a term to external binary format.
     */

    uint32_t io_threads; 

    ErlDrvBinary* input = ev->binv[1];
    char* bytes = input->orig_bytes;
    io_threads  = ntohl(*(uint32_t *)(bytes + 1));

    zmqdrv_fprintf("iothreads = %u\r\n", io_threads);

    if (drv->zmq_context) {
        zmqdrv_error_code(drv, EBUSY);
        return;
    }
    
    drv->zmq_context = (void *)zmq_init(io_threads);

    if (!drv->zmq_context) {
        zmqdrv_error_code(drv, zmq_errno());
        return;
    }

    zmqdrv_ok(drv);
}
Exemplo n.º 19
0
static void
zmqdrv_close(zmq_drv_t *drv, ErlIOVec *ev)
{
    ErlDrvBinary* bin   = ev->binv[1];
    char*         bytes = bin->orig_bytes;
    uint32_t      idx   = ntohl(*(uint32_t*)(bytes+1));

    if (idx > drv->zmq_socket_count) {
        zmqdrv_error_code(drv, ENODEV);
        return;
    }

    int ret = drv->del_socket(idx);

    zmqdrv_fprintf("close [idx=%d] -> %d\r\n", idx, ret);

    if (ret < 0) {
        zmqdrv_error_code(drv, zmq_errno());
        return;
    }
    
    zmqdrv_ok(drv);
}
Exemplo n.º 20
0
void zmq_drv_t::add_socket(zmq_sock_info* s)
{
    // Insert the new socket info to the head of the list
    if (zmq_sock_infos) zmq_sock_infos->prev = s;
    s->next        = zmq_sock_infos;
    zmq_sock_infos = s;

    // Update map: idx -> socket
    zmq_sockets[s->idx] = s;
    // Update map: socket -> idx
    zmq_idxs[s->socket] = s;
    {
        // Update map: pid -> sockets
        zmq_pid_sockets_map_t::iterator it = zmq_pid_sockets.find(s->owner);
        if (it != zmq_pid_sockets.end())
            it->second.sockets.insert(s);
        else {
            monitor_sockets_t ms;
            driver_monitor_process(port, s->owner, &ms.monitor);
            ms.sockets.insert(s);
            zmq_pid_sockets[s->owner] = ms;
        }
    }
    {
        // Update map: fd -> sockets
        zmq_fd_sockets_map_t::iterator it = zmq_fd_sockets.find(s->fd);
        if (it != zmq_fd_sockets.end())
            it->second.insert(s);
        else {
            zmq_sock_set_t set;
            set.insert(s);
            zmq_fd_sockets[s->fd] = set;
            driver_select(port, (ErlDrvEvent)s->fd, ERL_DRV_READ, 1);
            zmqdrv_fprintf("registered sig_fd(%d) with VM\r\n", s->fd);
        }
    }
}
Exemplo n.º 21
0
static void
zmqdrv_connect(zmq_drv_t *drv, ErlIOVec *ev)
{
    ErlDrvBinary* bin   = ev->binv[1];
    char*         bytes = bin->orig_bytes;
    uint32_t      idx   = ntohl(*(uint32_t*)(bytes+1));
    void*         s     = drv->get_zmq_socket(idx);
    uint16_t      size  = bin->orig_size - 5;
    char          addr[512];

    if (idx > drv->zmq_socket_count || !s) {
        zmqdrv_error_code(drv, ENODEV);
        return;
    }

    if (size > sizeof(addr) - 1) {
        zmqdrv_error_code(drv, E2BIG);
        return;
    }

    memcpy(addr, bytes + 5, size);
    addr[size] = '\0';

    zmqdrv_fprintf("connect %s\r\n", addr);

    if (!addr[0]) {
        zmqdrv_error_code(drv, EINVAL);
        return;
    }

    if (zmq_connect(s, addr) < 0) {
        zmqdrv_error_code(drv, zmq_errno());
        return;
    }

    zmqdrv_ok(drv);
}
Exemplo n.º 22
0
static void
zmqdrv_ready_input(ErlDrvData handle, ErlDrvEvent event)
{
    zmq_drv_t *drv = (zmq_drv_t *)handle;

    // Get 0MQ sockets managed by application thread's signaler
    // identified by "event" fd.
    zmq_fd_sockets_map_t::iterator it = drv->zmq_fd_sockets.find((long)event);

    zmqdrv_fprintf("input ready on [idx=%ld]\r\n", (long)event);

    assert(it != drv->zmq_fd_sockets.end());

    zmq_sock_set_t::iterator si = it->second.begin();

    assert(si != it->second.end());

    for (; si != it->second.end(); ++si) {
        zmq_socket_t   s     = (*si)->socket;
        uint32_t       idx   = (*si)->idx;
        ErlDrvTermData owner = (*si)->owner;
        int            rc    = 0;
        uint32_t       events;
        size_t         events_size = sizeof(events);

        zmq_getsockopt(s, ZMQ_EVENTS, &events, &events_size);

        while (((*si)->active_mode || (*si)->in_caller) && (events & ZMQ_POLLIN)) {
            msg_t msg;

            rc = zmq_recv(s, &msg, ZMQ_NOBLOCK);

            ErlDrvTermData pid = (*si)->active_mode ? owner : (*si)->in_caller;

            if (rc == -1) {
                if (zmq_errno() != EAGAIN) {
                    ErlDrvTermData spec[] =
                        {ERL_DRV_ATOM,  am_zmq,
                         ERL_DRV_UINT,  idx,
                         ERL_DRV_ATOM,  error_atom(zmq_errno()),
                         ERL_DRV_TUPLE, 2,
                         ERL_DRV_TUPLE, 3};
                    driver_send_term(drv->port, owner, spec, sizeof(spec)/sizeof(spec[0]));
                    (*si)->in_caller = 0;
                }
                break;
            }

            if ((*si)->active_mode) {
                // Send message {zmq, Socket, binary()} to the owner pid
                ErlDrvTermData spec[] =
                    {ERL_DRV_ATOM,  am_zmq,
                     ERL_DRV_UINT,  idx,
                     ERL_DRV_BUF2BINARY, (ErlDrvTermData)zmq_msg_data(&msg), zmq_msg_size(&msg),
                     ERL_DRV_TUPLE, 3};
                driver_send_term(drv->port, owner, spec, sizeof(spec)/sizeof(spec[0]));
            } else {
                // Return result {ok, binary()} to the waiting caller's pid
                ErlDrvTermData spec[] = 
                    {ERL_DRV_ATOM,   am_zok,
                     ERL_DRV_BUF2BINARY, (ErlDrvTermData)zmq_msg_data(&msg), zmq_msg_size(&msg),
                     ERL_DRV_TUPLE, 2};
                driver_send_term(drv->port, pid, spec, sizeof(spec)/sizeof(spec[0]));
                (*si)->in_caller = 0;
            }

            // FIXME: add error handling
            zmqdrv_fprintf("received %ld byte message relayed to pid %ld\r\n", zmq_msg_size(&msg), pid);
            zmq_getsockopt(s, ZMQ_EVENTS, &events, &events_size);
        }
    
        zmq_getsockopt(s, ZMQ_EVENTS, &events, &events_size);

        if ((*si)->out_caller != 0 && (events & ZMQ_POLLOUT)) {
            // There was a pending unwritten message on this socket.
            // Try to write it.  If the write succeeds/fails clear the ZMQ_POLLOUT
            // flag and notify the waiting caller of completion of operation.
            rc = zmq_send(s, &(*si)->out_msg, (*si)->out_flags | ZMQ_NOBLOCK);

            zmqdrv_fprintf("resending message %p (size=%ld) on socket %p (ret=%d)\r\n", 
                zmq_msg_data(&(*si)->out_msg), zmq_msg_size(&(*si)->out_msg), s, rc);

            if (rc == 0) {
                zmq_msg_close(&(*si)->out_msg);
                // Unblock the waiting caller's pid by returning result
                zmqdrv_ok(drv, (*si)->out_caller);
                (*si)->out_caller = 0;
            } else if (zmq_errno() != EAGAIN) {
                // Unblock the waiting caller's pid by returning result
                zmq_msg_close(&(*si)->out_msg);
                zmqdrv_socket_error(drv, (*si)->out_caller, idx, zmq_errno());
                (*si)->out_caller = 0;
            }
        }

        zmqdrv_fprintf("--> socket %p events=%d\r\n", s, events);
    }
}
Exemplo n.º 23
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static ErlDrvData
zmqdrv_start(ErlDrvPort port, char* /*cmd*/)
{
    zmqdrv_fprintf("zmq port driver started by pid %lu\r\n", driver_connected(port));
    return reinterpret_cast<ErlDrvData>(new zmq_drv_t(port));
}
Exemplo n.º 24
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static void
wrap_zmq_poll(zmq_drv_t *drv, const uint8_t* bytes, size_t size)
{
    uint32_t events = *bytes;

    assert(sizeof(uint8_t) == size);

    ErlDrvTermData caller = driver_caller(drv->port);

    if (drv->terminating)
    {
        reply_error(drv->port, caller, ETERM);
        return;
    }

    zmq_sock_info* si = drv->get_socket_info(caller);

    if (!si)
    {
        reply_error(drv->port, caller, ENODEV);
        return;
    }

    zmqdrv_fprintf("poll %p (events: %u)\r\n", si->socket, events);

    if (0 == events)
    {
        si->poll_events = 0;
        si->poll_caller = 0;

        if (si->busy && 0 == si->in_caller && 0 == si->out_caller)
        {
            driver_select(drv->port, si->fd, ERL_DRV_READ, 0);
            si->busy = false;
        }

        reply_ok(drv->port, caller);
        return;
    }

    if (si->busy)
    {
        reply_error(drv->port, caller, EBUSY);
        return;
    }

    assert((ZMQ_POLLIN|ZMQ_POLLOUT) & events);

    uint32_t revents;
    size_t revents_size = sizeof(revents);

    if (0 == zmq_getsockopt(si->socket, ZMQ_EVENTS, &revents, &revents_size))
    {
        // reply immediately; poll event notification happens out of band.
        reply_ok(drv->port, caller);

        revents &= events;

        if (0 != revents)
        {
            send_events(drv->port, caller, revents);
        }
        else
        {
            // No matching pending event, wait for one.
            zmqdrv_fprintf("poll %p blocking\r\n", si->socket);

            si->poll_events = events;
            si->poll_caller = caller;
            si->busy = true;
            driver_select(drv->port, si->fd, ERL_DRV_READ, 1);
        }
    }
    else
    {
        // EINVAL will only occur if our getsockopt call was invalid
        assert(EINVAL != zmq_errno());

        // else the problem was with the context/socket, and should be returned
        reply_error(drv->port, caller, zmq_errno());
    }
}
Exemplo n.º 25
0
/* Driver Stop, called on port close. */
static void
zmqdrv_stop(ErlDrvData handle)
{
    delete reinterpret_cast<zmq_drv_t*>(handle);
    zmqdrv_fprintf("driver stopped by pid\r\n");
}
Exemplo n.º 26
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static void
wrap_zmq_send(zmq_drv_t *drv, const uint8_t* bytes, size_t size, ErlDrvBinary* bin)
{
    int     flags     = *bytes;
    void*   data      = (void *)(bytes+sizeof(uint8_t));
    size_t  data_size = size - sizeof(uint8_t);

    assert(sizeof(uint8_t) <= size);

    ErlDrvTermData caller = driver_caller(drv->port);

    if (drv->terminating)
    {
        reply_error(drv->port, caller, ETERM);
        return;
    }

    zmq_sock_info* si = drv->get_socket_info(caller);

    if (!si)
    {
        reply_error(drv->port, caller, ENODEV);
        return;
    }

    assert(0 == si->out_caller);

    zmqdrv_fprintf("send %p (flags: %d bytes: %u)\r\n", si->socket, flags, data_size);

    // Increment the reference count on binary so that zmq can take ownership of it.
    driver_binary_inc_refc(bin);

    if (zmq_msg_init_data(&si->out_msg, data, data_size, &zmqcb_free_binary, bin))
    {
        reply_error(drv->port, caller, zmq_errno());
        driver_binary_dec_refc(bin);
        return;
    }

    if (0 == zmq_send(si->socket, &si->out_msg, flags|ZMQ_NOBLOCK))
    {
        reply_ok(drv->port, caller);
        zmq_msg_close(&si->out_msg);
    }
    else if (ZMQ_NOBLOCK != (ZMQ_NOBLOCK & flags) && EAGAIN == zmq_errno())
    {
        // Caller requested blocking send
        // Can't send right now. Make the caller wait by not returning result
        zmqdrv_fprintf("send %p blocking\r\n", si->socket);

        si->out_flags = flags;
        si->out_caller = caller;

        if (!si->busy)
        {
            driver_select(drv->port, si->fd, ERL_DRV_READ, 1);
            si->busy = true;
        }
    }
    else
    {
        reply_error(drv->port, caller, zmq_errno());
        zmq_msg_close(&si->out_msg);
    }
}
Exemplo n.º 27
0
static void
zmqdrv_ready_input(ErlDrvData handle, ErlDrvEvent event)
{
    zmq_drv_t *drv = (zmq_drv_t *)handle;

    // Get 0MQ sockets managed by application thread's signaler
    // identified by "event" fd.
    zmq_fd_sockets_map_t::iterator it = drv->zmq_fd_sockets.find((long)event);

    zmqdrv_fprintf("input ready on [idx=%ld]\r\n", (long)event);

    assert(it != drv->zmq_fd_sockets.end());

    zmq_sock_set_t::iterator si = it->second.begin();

    assert(si != it->second.end());

    for (; si != it->second.end(); ++si) {
        zmq_socket_t   s     = (*si)->socket;
        uint32_t       idx   = (*si)->idx;
        ErlDrvTermData owner = (*si)->owner;
        int            rc    = 0;
        uint32_t       events;
        size_t         events_size = sizeof(events);

        zmq_getsockopt(s, ZMQ_EVENTS, &events, &events_size);

        while (((*si)->active_mode || (*si)->in_caller) && (events & ZMQ_POLLIN)) {
            msg_t msg;

            rc = zmq_recv(s, &msg, ZMQ_NOBLOCK);

            ErlDrvTermData pid = (*si)->active_mode ? owner : (*si)->in_caller;

            if (rc == -1) {
                if (zmq_errno() != EAGAIN) {
                    ErlDrvTermData spec[] =
                        {ERL_DRV_ATOM,  am_zmq,
                         ERL_DRV_PORT,  driver_mk_port(drv->port),
                         ERL_DRV_UINT,  idx,
                         ERL_DRV_TUPLE, 2,
                         ERL_DRV_ATOM,  am_error,
                         ERL_DRV_ATOM,  error_atom(zmq_errno()),
                         ERL_DRV_TUPLE, 2,
                         ERL_DRV_TUPLE, 3};
                    driver_send_term(drv->port, owner, spec, sizeof(spec)/sizeof(spec[0]));
                    (*si)->in_caller = 0;
                }
                break;
            }

            if ((*si)->active_mode == 1) {

                // Send message {zmq, Socket, binary()} to the owner pid
                ErlDrvTermData spec[] =
                    {ERL_DRV_ATOM,  am_zmq,
                     ERL_DRV_PORT,  driver_mk_port(drv->port),
                     ERL_DRV_UINT,  idx,
                     ERL_DRV_TUPLE, 2,
                     ERL_DRV_BUF2BINARY, (ErlDrvTermData)zmq_msg_data(&msg), zmq_msg_size(&msg),
                     ERL_DRV_TUPLE, 3};
                driver_send_term(drv->port, owner, spec, sizeof(spec)/sizeof(spec[0]));

            } else if ((*si)->active_mode == 2) {

                // Send message {zmq, Socket, [binary()]} to the owner pid
                // where binary() is each message part
                std::vector<ErlDrvTermData> specv;
                specv.reserve(100);
                std::vector<msg_t*> parts;
                specv.push_back(ERL_DRV_ATOM);
                specv.push_back(am_zmq);
                specv.push_back(ERL_DRV_PORT);
                specv.push_back(driver_mk_port(drv->port));
                specv.push_back(ERL_DRV_UINT);
                specv.push_back(idx);
                specv.push_back(ERL_DRV_TUPLE);
                specv.push_back(2);
                specv.push_back(ERL_DRV_BUF2BINARY);
                specv.push_back((ErlDrvTermData)zmq_msg_data(&msg));
                specv.push_back(zmq_msg_size(&msg));
                int64_t more;
                size_t more_size = sizeof(more);
                int next_count = 0;
                while (true) {
                    zmq_getsockopt(s, ZMQ_RCVMORE, &more, &more_size);
                    if (!more)
                        break;
                    next_count += 1;
                    msg_t *next_part = new msg_t;
                    parts.push_back(next_part);
                    rc = zmq_recv(s, next_part, ZMQ_NOBLOCK);
                    assert (!rc); // FIXME
                    specv.push_back(ERL_DRV_BUF2BINARY);
                    specv.push_back((ErlDrvTermData)zmq_msg_data(next_part));
                    specv.push_back(zmq_msg_size(next_part));
                }
                specv.push_back(ERL_DRV_NIL);
                specv.push_back(ERL_DRV_LIST);
                specv.push_back(next_count + 2);
                specv.push_back(ERL_DRV_TUPLE);
                specv.push_back(3);
                driver_send_term(drv->port, owner, specv.data(), specv.size());
                for (uint i = 0; i < parts.size(); i++) {
                    delete parts[i];
                }

            } else {
                // Return result {ok, binary()} to the waiting caller's pid
                ErlDrvTermData spec[] = 
                    {ERL_DRV_ATOM,   am_zok,
                     ERL_DRV_BUF2BINARY, (ErlDrvTermData)zmq_msg_data(&msg), zmq_msg_size(&msg),
                     ERL_DRV_TUPLE, 2};
                driver_send_term(drv->port, pid, spec, sizeof(spec)/sizeof(spec[0]));
                (*si)->in_caller = 0;
            }

            // FIXME: add error handling
            zmqdrv_fprintf("received %ld byte message relayed to pid %ld\r\n", zmq_msg_size(&msg), pid);
            zmq_getsockopt(s, ZMQ_EVENTS, &events, &events_size);
        }
    
        zmq_getsockopt(s, ZMQ_EVENTS, &events, &events_size);

        if ((*si)->out_caller != 0 && (events & ZMQ_POLLOUT)) {
            // There was a pending unwritten message on this socket.
            // Try to write it.  If the write succeeds/fails clear the ZMQ_POLLOUT
            // flag and notify the waiting caller of completion of operation.
            rc = zmq_send(s, &(*si)->out_msg, (*si)->out_flags | ZMQ_NOBLOCK);

            zmqdrv_fprintf("resending message %p (size=%ld) on socket %p (ret=%d)\r\n", 
                zmq_msg_data(&(*si)->out_msg), zmq_msg_size(&(*si)->out_msg), s, rc);

            if (rc == 0) {
                zmq_msg_close(&(*si)->out_msg);
                // Unblock the waiting caller's pid by returning result
                zmqdrv_ok(drv, (*si)->out_caller);
                (*si)->out_caller = 0;
            } else if (zmq_errno() != EAGAIN) {
                // Unblock the waiting caller's pid by returning result
                zmq_msg_close(&(*si)->out_msg);
                zmqdrv_socket_error(drv, (*si)->out_caller, idx, zmq_errno());
                (*si)->out_caller = 0;
            }
        }

        zmqdrv_fprintf("--> socket %p events=%d\r\n", s, events);
    }
}
Exemplo n.º 28
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static void
wrap_zmq_getsockopt(zmq_drv_t *drv, const uint8_t* bytes, size_t size)
{
    int opt = *bytes;

    assert(sizeof(uint8_t) == size);

    ErlDrvTermData caller = driver_caller(drv->port);

    if (drv->terminating)
    {
        reply_error(drv->port, caller, ETERM);
        return;
    }

    zmq_sock_info* si = drv->get_socket_info(caller);

    if (!si)
    {
        reply_error(drv->port, caller, ENODEV);
        return;
    }

    zmqdrv_fprintf("getsockopt %p (opt: %d)\r\n", si->socket, opt);

    uint8_t optval[255] = {0};
    size_t optvallen = 0;
    void * p = (void*)optval;

    switch (opt)
    {
        case ZMQ_HWM:           optvallen = sizeof(uint64_t); break;
        case ZMQ_SWAP:          optvallen = sizeof(int64_t);  break;
        case ZMQ_AFFINITY:      optvallen = sizeof(uint64_t); break;
        case ZMQ_IDENTITY:      optvallen = sizeof(optval);   break;
        case ZMQ_RATE:          optvallen = sizeof(int64_t);  break;
        case ZMQ_RECOVERY_IVL:  optvallen = sizeof(int64_t);  break;
        case ZMQ_RECOVERY_IVL_MSEC: optvallen = sizeof(int64_t); break;
        case ZMQ_MCAST_LOOP:    optvallen = sizeof(int64_t);  break;
        case ZMQ_SNDBUF:        optvallen = sizeof(uint64_t); break;
        case ZMQ_RCVBUF:        optvallen = sizeof(uint64_t); break;
        case ZMQ_RCVMORE:       optvallen = sizeof(int64_t);  break;
        case ZMQ_LINGER:        optvallen = sizeof(int);      break;
        case ZMQ_RECONNECT_IVL: optvallen = sizeof(int);      break;
        case ZMQ_RECONNECT_IVL_MAX: optvallen = sizeof(int);  break;
        case ZMQ_BACKLOG:       optvallen = sizeof(int);      break;
        case ZMQ_FD:            optvallen = sizeof(int);      break;
        case ZMQ_EVENTS:        optvallen = sizeof(uint32_t); break;
        case ZMQ_TYPE:          optvallen = sizeof(int);      break;
        default:                assert(true);
    }

    if (0 != zmq_getsockopt(si->socket, opt, p, &optvallen))
    {
        reply_error(drv->port, caller, zmq_errno());
        return;
    }

    switch (opt)
    {
        // uint64
        case ZMQ_HWM:
        case ZMQ_AFFINITY:
        case ZMQ_SNDBUF:
        case ZMQ_RCVBUF:
            reply_ok_uint64(drv->port, caller, *(uint64_t*)p);
            break;

        // int64
        case ZMQ_SWAP:
        case ZMQ_RATE:
        case ZMQ_RECOVERY_IVL:
        case ZMQ_RECOVERY_IVL_MSEC:
            reply_ok_int64(drv->port, caller, *(int64_t*)p);
            break;

        // bool (from int64 0/1)
        case ZMQ_RCVMORE:
        case ZMQ_MCAST_LOOP:
            reply_ok_atom(drv->port, caller, *(int64_t*)p ? am_true : am_false);
            break;

        // ZMQ_POLLIN|ZMQ_POLLOUT (from uint32)
        case ZMQ_EVENTS:
            reply_ok_events(drv->port, caller, *(uint32_t*)p);
            break;

        // int
        case ZMQ_LINGER:
        case ZMQ_RECONNECT_IVL:
        case ZMQ_RECONNECT_IVL_MAX:
        case ZMQ_BACKLOG:
        case ZMQ_FD:
        case ZMQ_TYPE:
            reply_ok_int(drv->port, caller, *(int*)p);
            break;

        // binary
        case ZMQ_IDENTITY:
            reply_ok_binary(drv->port, caller, p, optvallen);
            break;
    }
}
Exemplo n.º 29
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static void
wrap_zmq_setsockopt(zmq_drv_t *drv, const uint8_t* bytes, size_t size)
{
    uint8_t        n = *bytes;
    const uint8_t* p =  bytes+sizeof(uint8_t);

    ErlDrvTermData caller = driver_caller(drv->port);

    if (drv->terminating)
    {
        reply_error(drv->port, caller, ETERM);
        return;
    }

    zmq_sock_info* si = drv->get_socket_info(caller);

    if (!si)
    {
        reply_error(drv->port, caller, ENODEV);
        return;
    }

    zmqdrv_fprintf("setsockopt %p (setting %d options)\r\n", si->socket, (int)n);

    for (uint8_t j = 0; j < n; ++j)
    {
        int         opt        = *p++;
        uint64_t    optvallen  = *p++;
        const void* optval     =  p;

        switch (opt)
        {
            case ZMQ_HWM:           assert(optvallen == sizeof(uint64_t));break;
            case ZMQ_SWAP:          assert(optvallen == sizeof(int64_t)); break;
            case ZMQ_AFFINITY:      assert(optvallen == sizeof(uint64_t));break;
            case ZMQ_IDENTITY:      assert(optvallen <= 255);             break;
            case ZMQ_SUBSCRIBE:     break; // While the erlang layer limits this to 255, there is no zmq limit
            case ZMQ_UNSUBSCRIBE:   break; // While the erlang layer limits this to 255, there is no zmq limit
            case ZMQ_RATE:          assert(optvallen == sizeof(int64_t)); break;
            case ZMQ_RECOVERY_IVL:  assert(optvallen == sizeof(int64_t)); break;
            case ZMQ_RECOVERY_IVL_MSEC: assert(optvallen == sizeof(int64_t)); break;
            case ZMQ_MCAST_LOOP:    assert(optvallen == sizeof(int64_t)); break;
            case ZMQ_SNDBUF:        assert(optvallen == sizeof(uint64_t));break;
            case ZMQ_RCVBUF:        assert(optvallen == sizeof(uint64_t));break;
            case ZMQ_LINGER:        assert(optvallen == sizeof(int));     break; // Erlang layer assumes 32bit
            case ZMQ_RECONNECT_IVL: assert(optvallen == sizeof(int));     break; // Erlang layer assumes 32bit
            case ZMQ_RECONNECT_IVL_MAX: assert(optvallen == sizeof(int)); break; // Erlang layer assumes 32bit
            case ZMQ_BACKLOG:       assert(optvallen == sizeof(int));     break; // Erlang layer assumes 32bit
            default:                assert(true);
        }

        assert((size_t)((uint8_t*)(p + optvallen) - bytes) <= size);

        zmqdrv_fprintf("setsockopt %p (opt: %d)\r\n", si->socket, opt);

        if (0 != zmq_setsockopt(si->socket, opt, optval, optvallen))
        {
            reply_error(drv->port, caller, zmq_errno());
            return;
        }

        p += optvallen;
    }

    reply_ok(drv->port, caller);
}
Exemplo n.º 30
0
static void 
zmqdrv_getsockopt(zmq_drv_t *drv, ErlIOVec *ev)
{
    ErlDrvBinary*   bin   = ev->binv[1];
    char*           bytes = bin->orig_bytes;
    uint32_t        idx   = ntohl(*(uint32_t*)(bytes+1));
    void*           s     = drv->get_zmq_socket(idx);
    zmq_sock_info*  si    = drv->get_socket_info(idx);
    uint32_t        opt   = ntohl (*(uint32_t*)(bytes+sizeof(idx)+1));
    union {
        uint8_t  a[255];
        uint64_t ui64;
        int64_t  i64;
        int      i;
        uint32_t ui;
    } val;
    size_t vallen;

    if (idx > drv->zmq_socket_count || !s || !si) {
        zmqdrv_error_code(drv, ENODEV);
        return;
    }

    zmqdrv_fprintf("setsockopt %p (setting %d options)\r\n", si->socket, (int)n);

    switch (opt) {
        case ZMQ_AFFINITY:
            vallen = sizeof(uint64_t);
            if (zmq_getsockopt(s, opt, &val.ui64, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_int64(drv, driver_caller(drv->port), val.ui64);
            break;
        case ZMQ_BACKLOG:
            vallen = sizeof(int);
            if (zmq_getsockopt(s, opt, &val.i, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i);
            break;
        case ZMQ_EVENTS:
            vallen = sizeof(uint32_t);
            if (zmq_getsockopt(s, opt, &val.ui, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_int64(drv, driver_caller(drv->port), val.ui);
            break;
        case ZMQ_FD:
            vallen = sizeof(int);
            if (zmq_getsockopt(s, opt, &val.i, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i);
            break;
        case ZMQ_HWM:
            vallen = sizeof(uint64_t);
            if (zmq_getsockopt(s, opt, &val.ui64, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_int64(drv, driver_caller(drv->port), val.ui64);
            break;
        case ZMQ_IDENTITY:
            vallen = sizeof(val);
            if (zmq_getsockopt(s, opt, val.a, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_binary(drv, driver_caller(drv->port), val.a, vallen);
            break;
        case ZMQ_LINGER:
            vallen = sizeof(int);
            if (zmq_getsockopt(s, opt, &val.i, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_bool(drv, driver_caller(drv->port), !!val.i);
            break;
        case ZMQ_MCAST_LOOP:
            vallen = sizeof(int64_t);
            if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_bool(drv, driver_caller(drv->port), !!val.i64);
            break;
        case ZMQ_RATE:
            vallen = sizeof(int64_t);
            if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i64);
            break;
        case ZMQ_RCVBUF:
            vallen = sizeof(uint64_t);
            if (zmq_getsockopt(s, opt, &val.ui64, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_int64(drv, driver_caller(drv->port), val.ui64);
            break;
        case ZMQ_RCVMORE:
            vallen = sizeof(int64_t);
            if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_bool(drv, driver_caller(drv->port), !!val.i64);
            break;
        case ZMQ_RECONNECT_IVL:
            vallen = sizeof(int);
            if (zmq_getsockopt(s, opt, &val.i, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i);
            break;
        case ZMQ_RECOVERY_IVL:
            vallen = sizeof(int64_t);
            if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i64);
            break;
        case ZMQ_RECOVERY_IVL_MSEC:
            vallen = sizeof(int64_t);
            if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i64);
            break;
        case ZMQ_SNDBUF:
            vallen = sizeof(uint64_t);
            if (zmq_getsockopt(s, opt, &val.ui64, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_int64(drv, driver_caller(drv->port), val.ui64);
            break;
        case ZMQ_SWAP:
            vallen = sizeof(int64_t);
            if (zmq_getsockopt(s, opt, &val.i64, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i64);
            break;
        case ZMQ_TYPE:
            vallen = sizeof(int);
            if (zmq_getsockopt(s, opt, &val.i, &vallen) < 0)
                zmqdrv_error_code(drv, zmq_errno());
            zmqdrv_ok_int64(drv, driver_caller(drv->port), val.i);
            break;
        case ZMQ_ACTIVE:
            zmqdrv_ok_atom(drv, driver_caller(drv->port),
                           (si->active_mode == 1 ? am_true :
                            (si->active_mode == 2 ? am_parts :
                             am_false)));
            break;
        default:
            zmqdrv_error(drv, "Option not implemented!");
            return;
    }
}