Example #1
0
static ErlDrvData
start(ErlDrvPort port, char *command)
{
    mcd_data_t *mcd = driver_alloc(sizeof(mcd_data_t));

    if (!mcd)
	goto error;

    mcd->ofd = -1;
    mcd->ifd = -1;

#ifdef UNIX

    mcd->ofd = open("/dev/null", O_WRONLY);
    if (mcd->ofd < 0)
	goto error;
    if (driver_select(port, (ErlDrvEvent) (long) mcd->ofd, DO_WRITE, 1) != 0)
	goto error;

    mcd->ifd = open("/dev/zero", O_RDONLY);
    if (mcd->ifd < 0)
	goto error;
    if (driver_select(port, (ErlDrvEvent) (long) mcd->ifd, DO_READ, 1) != 0)
	goto error;
#endif

    driver_set_timer(port, 0);

    return (ErlDrvData) mcd;

 error:
    stop((ErlDrvData) mcd);
    return ERL_DRV_ERROR_GENERAL;
}
Example #2
0
File: enm_drv.c Project: basho/enm
int
enm_write_select(EnmData* d, int start)
{
    ErlDrvEvent event;
    int rc;
    size_t optlen = sizeof d->sfd;

    if (start) {
        if (d->b.write_poll)
            return 0;
        if (d->sfd == -1) {
            if (d->protocol == NN_PULL || d->protocol == NN_SUB) {
                errno = EINVAL;
                return -1;
            }
            rc = nn_getsockopt(d->fd, NN_SOL_SOCKET, NN_SNDFD, &d->sfd, &optlen);
            if (rc < 0)
                return -1;
            enm_sockets[d->sfd] = d;
        }
        event = (ErlDrvEvent)(long)d->sfd;
        driver_select(d->port, event, ERL_DRV_WRITE|ERL_DRV_USE, 1);
        d->b.write_poll = 1;
    } else {
        if (!d->b.write_poll)
            return 0;
        assert(d->sfd != -1);
        event = (ErlDrvEvent)(long)d->sfd;
        driver_select(d->port, event, ERL_DRV_WRITE|ERL_DRV_USE, 0);
        d->b.write_poll = 0;
    }
    return 0;
}
Example #3
0
void dthread_signal_use(dthread_t* thr, int on)
{
#ifdef __WIN32__
    driver_select(thr->port,thr->iq_signal[0],ERL_DRV_USE,on);
#else
    driver_select(thr->port,thr->iq_signal[1],ERL_DRV_USE,on);
    driver_select(thr->port,thr->iq_signal[0],ERL_DRV_USE,on);
#endif
}
Example #4
0
void dthread_signal_select(dthread_t* thr, int on)
{
    DEBUGF("dthread_signal_select: fd=%d", 
	   DTHREAD_EVENT(thr->iq_signal[0]));
#ifdef __WIN32__
    driver_select(thr->port,thr->iq_signal[0],ERL_DRV_READ,on);
#else
    driver_select(thr->port,thr->iq_signal[0],ERL_DRV_READ,on);
#endif
}
Example #5
0
static void sendfile_drv_ready_output(ErlDrvData handle, ErlDrvEvent ev)
{
    Desc* d = (Desc*)handle;
    ssize_t result;
    off_t cur_offset;
    Transfer* xfer;
    SocketFd* sfd = (SocketFd*)&ev;
    xfer = (Transfer*)hashtable_search(d->xfer_table, sfd->hashkey);
    if (xfer == NULL) {
        /* fatal error, something is very wrong */
        driver_failure_atom(d->port, "socket_fd_not_found");
        return;
    }
    cur_offset = xfer->offset;
    result = sendfile_call(sfd->socket_fd, xfer->file_fd,
                           &xfer->offset, xfer->count);
    if (result < 0 && (errno == EAGAIN || errno == EWOULDBLOCK ||
                       errno == EINPROGRESS || errno == EALREADY)) {
        if (xfer->offset != cur_offset) {
            off_t written = xfer->offset - cur_offset;
            xfer->count -= written;
            xfer->total += written;
        }
    } else {
        int save_errno = errno;
        ErlDrvSizeT out_buflen;
        char buf[36];
        Buffer b;
        b.buffer = buf;
        memset(buf, 0, sizeof buf);
#ifdef ERL_DRV_WRITE
        driver_select(d->port, ev, ERL_DRV_WRITE, 0);
#else
        driver_select(d->port, ev, DO_WRITE, 0);
#endif
        close(xfer->file_fd);
        if (result < 0) {
            out_buflen = set_error_buffer(&b, sfd->socket_fd, save_errno);
        } else {
            uint64_t total = xfer->total + result;
            put_int64(total, &(b.result->count.count));
            put_int32(sfd->socket_fd, &(b.result->out_fd));
            b.result->success = 1;
            b.result->errno_string[0] = '\0';
            out_buflen = sizeof(*b.result);
        }
        xfer->file_fd = -1;
        xfer->offset = xfer->count = xfer->total = 0;
        driver_output(d->port, buf, out_buflen);
    }
}
Example #6
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);
}
Example #7
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");
    }
}
Example #8
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;
}
Example #9
0
static void uvc_drv_stop(ErlDrvData handle)
{
  Uvc* d = (Uvc *)handle;
  driver_select(d->port, (ErlDrvEvent)d->fd, DO_READ|DO_WRITE, 0);
  
  int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	ioctl(d->fd, VIDIOC_STREAMOFF, &type);
  
  
  int i;
  for(i = 0; i < d->nbufs; i++) {
    munmap(d->buffers[i].mem, d->buffers[i].size);
  }
  
  struct v4l2_requestbuffers rb;
  memset(&rb, 0, sizeof rb);
  rb.count = 0;
  rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  rb.memory = V4L2_MEMORY_MMAP;
  ioctl(d->fd, VIDIOC_REQBUFS, &rb);
  free(d->buffers);
  
  close(d->fd);
  driver_free((char*)handle);
}
Example #10
0
static void sendfile_drv_output(ErlDrvData handle, char* buf,
                                ErlDrvSizeT buflen)
{
    int fd, socket_fd;
    Desc* d = (Desc*)handle;
    Buffer b;
    b.buffer = buf;
    socket_fd = get_int32(&(b.args->out_fd));
    fd = open(b.args->filename, O_RDONLY | O_NONBLOCK);
    if (fd < 0) {
        ErlDrvSizeT out_buflen = set_error_buffer(&b, socket_fd, errno);
        driver_output(d->port, buf, out_buflen);
    } else {
        Transfer* xfer;
        SocketFd sfd;
        sfd.socket_fd = socket_fd;
        xfer = (Transfer*)hashtable_search(d->xfer_table, sfd.hashkey);
        if (xfer == NULL) {
            /* Transfer objects are intentionally not freed until the
               driver stops, or if an insertion error occurs below. */
            xfer = (Transfer*)malloc(sizeof(Transfer));
            if (xfer == NULL) {
                ErlDrvSizeT out_buflen = set_error_buffer(&b, socket_fd,
                                                          ENOMEM);
                driver_output(d->port, buf, out_buflen);
                return;
            }
            if (!hashtable_insert(d->xfer_table, sfd.hashkey, xfer)) {
                ErlDrvSizeT out_buflen = set_error_buffer(&b, socket_fd,
                                                          ENOMEM);
                driver_output(d->port, buf, out_buflen);
                free(xfer);
                return;
            }
        }
        xfer->file_fd = fd;
        xfer->offset = get_int64(&(b.args->offset.offset));
        xfer->count = get_int64(&(b.args->count.size));
        xfer->total = 0;
#if defined(ERL_DRV_USE) && defined(ERL_DRV_WRITE)
        driver_select(d->port, sfd.ev_data, ERL_DRV_USE|ERL_DRV_WRITE, 1);
#else
        driver_select(d->port, sfd.ev_data, DO_WRITE, 1);
#endif
    }
}
Example #11
0
void do_initscr(state *st) {
  st->win[0] = (WINDOW *)initscr();
  driver_select(st->drv_port, (ErlDrvEvent)(size_t)fileno(stdin), DO_READ, 1);
  if (st->win[0] == NULL) {
    encode_ok_reply(st, -1);
  } else {
    encode_ok_reply(st, 0);
  }
}
Example #12
0
/*
 * Called when the Erlang port is closed.
 */
static void stop(ErlDrvData drv_data)
{
    /* make sure we stop Erlang from selecting on fdsrv */
    driver_select(instance, fdsrv, DO_READ, 0);

    /* cleanup */
    close((int)(long)fdsrv);
    instance = (ErlDrvPort) -1;
}
Example #13
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);
}
Example #14
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));
}
Example #15
0
/*
 * Called when the Erlang port is closed.
 */
static void stop(ErlDrvData drv_data)
{
    /* make sure we stop Erlang from selecting on fdsrv */
    driver_select(instance, fdsrv, DO_READ, 0);

    /* cleanup */
    close(fdsrv);
    instance = -1;
    
    return;
}
Example #16
0
static void stop(ErlDrvData edd) {
  dnssd_drv_t* dd = (dnssd_drv_t*) edd;
#ifdef __WIN32__
  if (dd->event) {
    driver_select(dd->erl_port, dd->event, DO_READ, 0);
    WSAEventSelect(DNSServiceRefSockFD(dd->sd_ref), NULL, 0);
  }
  if (dd->sd_ref) {
    DNSServiceRefDeallocate(dd->sd_ref);
  }
#else
  if (dd->sd_ref) {
    driver_select(dd->erl_port,
		  (ErlDrvEvent)(size_t) DNSServiceRefSockFD(dd->sd_ref),
		  DO_READ,
		  0);
    DNSServiceRefDeallocate(dd->sd_ref);
  }
#endif
  driver_free(dd);
}
Example #17
0
/*
 * Called when the Erlang port is closed.
 */
static void log_stop()
{
#if 0
    /* make sure we stop Erlang from selecting on fdsrv */
    driver_select(instance, fdsrv, DO_READ, 0);
    instance = -1;
#endif

    closelog();

    /* cleanup */
    close(log_port);
    
    return;
}
Example #18
0
static int do_disconnect(our_data_t* data)
{
    ei_x_buff x;

    if (data->socket == 0)
	return 0;
    driver_select(data->port, (ErlDrvEvent)data->socket, DO_READ, 0);
    data->socket = 0;
    PQfinish(data->conn);
    data->conn = NULL;
    ei_x_new_with_version(&x);
    encode_ok(&x);
    driver_output(data->port, x.buff, x.index);
    ei_x_free(&x);
    return 0;
}
Example #19
0
static void
io_ready_exit_drv_stop(ErlDrvData drv_data) {
    IOReadyExitDrvData *oeddp = (IOReadyExitDrvData *) drv_data;
#ifdef UNIX
    if (oeddp->fds[0] >= 0) {
	driver_select(oeddp->port,
		      (ErlDrvEvent) oeddp->fds[0],
		      DO_READ|DO_WRITE,
		      0);
	close(oeddp->fds[0]);
    }
    if (oeddp->fds[1] >= 0)
	close(oeddp->fds[1]);
#endif
    driver_free((void *) oeddp);
}
Example #20
0
/* pending getkey request */
sl_ready_input(int port, int fd)
{
    unsigned int key;
    driver_select(port, 0, DO_READ, 0);
    switch (wait_for) {
    case GETKEY: {
	key = SLang_getkey ();
	return ret_int(port, key);
    }
    case KP_GETKEY: {
	key = SLkp_getkey ();
	return ret_int(port, key);
    }
    return 0;
    }	
}
Example #21
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;
}
Example #22
0
static int do_connect(const char *s, our_data_t* data)
{
    ei_x_buff x;
    PGconn* conn = PQconnectdb(s);

    ei_x_new_with_version(&x);
    if (PQstatus(conn) != CONNECTION_OK) {
        encode_error(&x, conn);
	PQfinish(conn);
	conn = NULL;
    } else {
        encode_ok(&x);
	data->socket = PQsocket(conn);
	driver_select(data->port, (ErlDrvEvent)data->socket, DO_READ, 1);
    }
    driver_output(data->port, x.buff, x.index);
    ei_x_free(&x);
    data->conn = conn;
    return 0;
}
Example #23
0
/*
 * Called when erlang side does "open_port()".
 */
static ErlDrvData log_start(ErlDrvPort port, char * buf)
{
    log_port = port;

#if 0
    int len;
    char *path;
    struct sockaddr_un addr;


    /* only allow one copy at the time */
    if (instance != -1)		return -1;
    if (strlen(buf) > (sizeof(addr.sun_path) + 1)) return -1;
    instance = port;

    /* Figure out the path to the named socket */
    if ((path = strrchr(buf, (int)' ')) == NULL) path = buf;
    else path++;

    fdsrv = socket(AF_UNIX, SOCK_STREAM, 0);
    bzero((char *)&addr, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, path);
    len = strlen(path) + sizeof(addr.sun_family) + 1;

    if (connect(fdsrv, (struct sockaddr *)&addr, len) < 0) 
    {
        perror("connect");
        instance = -1;
        return -1;
    }

    
    /* Have Erlang select on fdsrv */
    driver_select(port, fdsrv, DO_READ, 1);
#endif
    /* Open syslog */
    openlog("Eddie", 0, LOG_DAEMON);

    return port;
}
Example #24
0
/*
 * Called when select triggers. Which is when there is an incomming fd.
 */
static void fd_is_ready(ErlDrvData drv_data, ErlDrvEvent event)
{
    ErlDrvPort port = (ErlDrvPort) drv_data;
    int received_fd;

    if (port != instance)
        return;
    if (event != fdsrv)
        return;

    /* receive the file descriptor */
    recv_fd(port, &received_fd, fdsrv);

    if (received_fd < 0) {
        close((int)(long)fdsrv);
        driver_select(port, fdsrv, DO_READ, 0);
        reply_err(port);
    }
    else
        reply_int(port, received_fd);
}
Example #25
0
static int
io_ready_exit_drv_control(ErlDrvData drv_data,
			  unsigned int command,
			  char *buf, int len,
			  char **rbuf, int rlen)
{
    char *abuf;
    char *res_str;
    int res_len;
    IOReadyExitDrvData *oeddp = (IOReadyExitDrvData *) drv_data;
#ifndef UNIX
    res_str = "nyiftos";
#else
    if (pipe(oeddp->fds) < 0) {
	res_str = "pipe failed";
    }
    else {
	res_str = "ok";
	write(oeddp->fds[1], "!", 1);
	driver_select(oeddp->port,
		      (ErlDrvEvent) oeddp->fds[0],
		      DO_READ|DO_WRITE,
		      1);
    }
#endif
    res_len = strlen(res_str);
    if (res_len > rlen) {
	abuf = driver_alloc(sizeof(char)*res_len);
	if (!abuf)
	    return 0;
	*rbuf = abuf;
    }

    memcpy((void *) *rbuf, (void *) res_str, res_len);

    return res_len;
}
Example #26
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);
        }
    }
}
Example #27
0
/*
 * Called when erlang side does "open_port()".
 */
static ErlDrvData start(ErlDrvPort port, char *buf)
{
    int len;
    char *path;
    struct sockaddr_un addr;
    int s;

    if (instance != (ErlDrvPort) -1)   /* only allow one copy at the time */
        return (ErlDrvData) -1;
    if (strlen(buf) > (sizeof(addr.sun_path) + 1))
        return (ErlDrvData) -1;
    instance = port;

    /* Figure out the path to the named socket */
    if ((path = strrchr(buf, (int)' ')) == NULL)
        path = buf;
    else
        path++;

    s = socket(AF_UNIX, SOCK_STREAM, 0);
    bzero((char *)&addr, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, path);
    len = strlen(path) + sizeof(addr.sun_family) + 1;

    if (connect(s, (struct sockaddr *)&addr, len) < 0) {
        perror("connect");
        instance = (ErlDrvPort) -1;
        return (ErlDrvData) -1;
    }
    fdsrv = (ErlDrvEvent)(long)s;
    /* Have Erlang select on fdsrv */
    driver_select(port, fdsrv, DO_READ, 1);

    return (ErlDrvData) port;
}
Example #28
0
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
static void
zmqdrv_ready_input(ErlDrvData handle, ErlDrvEvent event)
{
    zmq_drv_t *drv = reinterpret_cast<zmq_drv_t*>(handle);
    zmq_sock_info *si = drv->get_socket_info(event);

    // I'm not sure if a race condition could develop here or not
    // So let's assert and see if we ever hit it.  Hopefully not.
    assert(!drv->terminating);
    assert(NULL != si);
    assert(si->busy);

    // unregister event with erlang vm while we work with the socket
    driver_select(drv->port, si->fd, ERL_DRV_READ, 0);

    // Finish blocking recv request if input is ready
    if (si->in_caller)
    {
        zmq_msg_t msg;
        zmq_msg_init(&msg);

        if (0 == zmq_recv(si->socket, &msg, si->in_flags|ZMQ_NOBLOCK))
        {
            // Unblock the waiting caller's pid by returning result
            reply_ok_binary(drv->port, si->in_caller, zmq_msg_data(&msg), zmq_msg_size(&msg));
            si->in_caller = 0;
            si->in_flags = 0;
        }
        else if (zmq_errno() != EAGAIN)
        {
            // Unblock the waiting caller's pid by returning error
            reply_error(drv->port, si->in_caller, zmq_errno());
            si->in_caller = 0;
            si->in_flags = 0;
        }
        // else no input was ready, continue waiting

        zmq_msg_close(&msg);
    }

    // Finish blocking send request if able
    if (si->out_caller)
    {
        if (0 == zmq_send(si->socket, &si->out_msg, si->out_flags|ZMQ_NOBLOCK))
        {
            // Unblock the waiting caller's pid by returning result
            reply_ok(drv->port, si->out_caller);
            si->out_caller = 0;
            si->out_flags = 0;
            zmq_msg_close(&si->out_msg);
        }
        else if (zmq_errno() != EAGAIN)
        {
            // Unblock the waiting caller's pid by returning error
            reply_error(drv->port, si->out_caller, zmq_errno());
            si->out_caller = 0;
            si->out_flags = 0;
            zmq_msg_close(&si->out_msg);
        }
        // else not able to send, continue waiting
    }

    // Finish poll request if events available
    if (si->poll_caller)
    {
        uint32_t revents = 0;
        size_t revents_size = sizeof(revents);

        if (0 == zmq_getsockopt(si->socket, ZMQ_EVENTS, &revents, &revents_size))
        {
            revents &= si->poll_events;

            if (0 != revents)
            {
                send_events(drv->port, si->poll_caller, revents);
                si->poll_caller = 0;
                si->poll_events = 0;
            }
            // else no requested events pending, continue waiting
        }
        else
        {
            // EINVAL will only occur if our getsockopt call was invalid
            assert(EINVAL != zmq_errno());

            // send out of band event error notification
            send_events(drv->port, si->poll_caller, (uint32_t)ZMQ_POLLERR);
            si->poll_caller = 0;
            si->poll_events = 0;
        }
    }

    // reregister event with erlang vm if any pending operations exist
    if (si->poll_caller || si->in_caller || si->out_caller)
    {
        driver_select(drv->port, si->fd, ERL_DRV_READ, 1);
    }
    else
    {
        si->busy = false;
    }
}
Example #29
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());
    }
}
Example #30
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);
    }
}