Exemplo n.º 1
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.º 2
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);
    }
}