Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
895 lines (800 sloc) 27 KB
/*
** File : unixdom_drv.c
** Summary : EDTK implementation of UNIX domain socket driver (incomplete!)
**
** NOTICE: This file was generated by the tools of the Erlang Driver
** toolkit. Do not edit this file by hand unless you know
** what you're doing!
**
** Copyright (c) 2004, Scott Lystig Fritchie. All rights reserved.
** See the file "LICENSE" at the top of the source distribution for
** full license terms.
*/
/*
** XXX Before I forget yet again to write this down...
**
** ... the valmap ID assignment has a weakness that should be fixed
** sometime in the future. The weakness is that reusing the array
** indexes could result in Erlang being able to access a later
** incarnation of a valmap table entry by simply remembering a
** previous valmap {valmap_blah, Integer} and resending it to the
** driver, hoping to get (un)lucky.
**
** The solution would be to choose a valmap index from a larger, very
** unlikely to repeat set, and use a mapping data structure less naive
** than a dumb array.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <assert.h>
#ifdef DRIVER_USING_PTHREADS
#include <pthread.h>
#else /* DRIVER_USING_PTHREADS */
#define pthread_self() 0
#endif /* DRIVER_USING_PTHREADS */
/* TODO: Add additional system & local header file #includes */
#include <erl_driver.h>
#include <erl_driver_tk.h>
/* <verbatim place="top_cpp_stuff"> */
#include <stdio.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h> /* htonl() et al. */
#include <my-unixdom.h>
/* </verbatim --place="top_cpp_stuff"--> */
/* Last, but not least.... */
#include <unixdom_drv.h>
static ErlDrvTermData am_ok;
static ErlDrvTermData am_error;
static ErlDrvTermData am_badarg;
static ErlDrvTermData am_enomem;
static ErlDrvTermData am_unknown;
static ErlDrvTermData am_valmap_fd;
static int default_async_calls = 0;
/* This variable may be set only by pipe-main! */
int pipe_driver_p = 0;
/*
** TODO: Define any other Erlang terms this driver may return.
*/
/* Function prototypes */
ErlDrvEntry *driver_init(void *); /* Do not change name! */
static int s1_init(void);
static ErlDrvData s1_start(ErlDrvPort port, char *command);
static void s1_stop(ErlDrvData drv_data);
static void s1_output(ErlDrvData drv_data, char *buf, int len);
static int s1_control(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen);
static void s1_outputv(ErlDrvData drv_data, ErlIOVec *ev);
static void s1_ready_async(ErlDrvData drv_data, ErlDrvThreadData thread_data);
void *sys_alloc(size_t);
void *sys_realloc(void *, size_t);
void sys_free(void *);
static void invoke_s1_null(void *data);
static void invoke_s1_open(void *data);
static void invoke_s1_getfd(void *data);
static void invoke_s1_sendfd(void *data);
static void invoke_s1_receivefd(void *data);
static void invoke_s1_close(void *data);
static void invoke_s1_write(void *data);
static void invoke_s1_read(void *data);
static int reply_xtra_1_ptr_ssize_t(descriptor_t *, callstate_t *);
static int find_unused_fd_index(descriptor_t *, unsigned long *);
static void cleanup_valmap_fd_index(descriptor_t *, int, int);
static void cleanup_valmap_fd_all(descriptor_t *, int);
static int reply_ok(descriptor_t *desc);
static int reply_ok_num(descriptor_t *desc, unsigned long num);
static int reply_ok_binary(descriptor_t *desc, char *p, int, int);
static int reply_ok_valmap(descriptor_t *, ErlDrvTermData, unsigned long);
static int reply_error(descriptor_t *desc, int errnum);
static int reply_error_atom(descriptor_t *, ErlDrvTermData);
#if 0
static int reply_tag_ok(descriptor_t *desc, unsigned short tag);
static int reply_tag_error(descriptor_t *desc, unsigned short tag, int errnum);
#endif /* 0 */
static ErlDrvEntry s1_driver_entry = {
s1_init, /* init */
s1_start, /* start */
s1_stop, /* stop */
s1_output, /* output */
NULL, /* ready_input */
NULL, /* ready_output */
"unixdom_drv", /* driver_name */
NULL, /* finish */
NULL, /* handle */
s1_control, /* control */
NULL, /* timeout */
s1_outputv, /* outputv */
s1_ready_async, /* ready_async */
NULL, /* flush */
NULL /* call */
};
/*
** All dynamically-loadable driver libraries must contain a driver_init().
*/
ErlDrvEntry *
driver_init(void *handle)
{
edtk_debug_flag = 0;
s1_driver_entry.handle = handle;
return &s1_driver_entry;
}
static int
s1_init(void)
{
am_ok = driver_mk_atom("ok");
am_error = driver_mk_atom("error");
am_badarg = driver_mk_atom("badarg");
am_enomem = driver_mk_atom("enomem");
am_unknown = driver_mk_atom("unknown");
am_valmap_fd = driver_mk_atom("valmap_fd");
/* TODO: Take care of other first-time initialization tasks */
return 0;
}
static ErlDrvData
s1_start(ErlDrvPort port, char *args)
{
descriptor_t *desc;
int i = 0;
i = i;
edtk_debug("%s: starting, port = %ld, args = 0x%lx, %s", __FUNCTION__,
port, (unsigned long) args, args);
if ((desc = (descriptor_t *) sys_alloc(sizeof(descriptor_t))) == NULL) {
return ERL_DRV_ERROR_GENERAL;
}
memset(desc, 0, sizeof(descriptor_t));
desc->port = port;
desc->nextxid = 1;
for (i = 0; i < 32; i++) {
desc->valmap_fd[i] = -1;
}
/* TODO: Finish initializing descriptor members */
/* TODO: Take care of other port initialization tasks */
return (ErlDrvData) desc;
}
static void
s1_stop(ErlDrvData drv_data)
{
descriptor_t *desc = (descriptor_t *) drv_data;
int i = 0;
ErlDrvPort port;
int still_in_use = 0;
i = i;
if (desc == NULL) {
edtk_debug("%s: drv_data == NULL", __FUNCTION__);
return;
}
edtk_debug("%s: port = %ld", __FUNCTION__, desc->port);
for (i = 0; i < 32; i++) {
if (desc->valmap_fd[i] != -1) {
cleanup_valmap_fd_index(desc, i, 1);
}
}
if (! still_in_use) {
port = desc->port;
sys_free(desc);
edtk_debug("%s: port = %ld finished", __FUNCTION__, port);
} else {
/*
** XXX Oi, this is a sticky problem. This port is being shut
** down, but we've still got some valmaps in use. We have no
** way to tell the VM that we cannot be shut down safely right
** now, so what in the heck do we do? It seems to me that we
** have two choices:
** 1. Block the entire VM until all valmaps are idle, then
** clean them up and then return.
** 2. Create a new thread that will take care of monitoring
** the valmaps & doing their final cleanup. This stop
** function, executing in the main thread, can return
** to the VM right away.
** For the sake of simplicity, I'm going to implement #1
** for now. This will get more complicated once EDTK supports
** private worker threads, so we won't bother getting fancy
** for now.
*/
edtk_debug("%s: port = %ld has %d valmaps still in use!", __FUNCTION__, desc->port, still_in_use);
sleep(1);
s1_stop(drv_data); /* Hope we don't run out of stack */
}
}
static void
s1_output(ErlDrvData drv_data, char *buf, int len)
{
/*
** Nobody should be calling this function because we've
** defined the "outputv" driver method, which BEAM will always
** used if it's available. I just put a debug statement in
** here so that I might actually notice if the impossible ever
** happens....
*/
edtk_debug("%s: XXX someone tried to call us, silly", __FUNCTION__);
}
static int
s1_control(ErlDrvData drv_data, unsigned int command,
char *buf, int len, char **rbuf, int rlen)
{
char *ret = *rbuf;
int retlen;
/*
** Nobody should be calling this function either.
*/
ret[0] = 1;
retlen = 1;
edtk_debug("%s: XXX someone tried to call us, silly", __FUNCTION__);
return retlen;
}
static void
s1_outputv(ErlDrvData drv_data, ErlIOVec *ev)
{
descriptor_t *desc = (descriptor_t *) drv_data;
unsigned char cmd;
int p = 0, q = 1;
callstate_t *c = NULL;
int do_async_call = default_async_calls;
unsigned long binlen;
int index;
void *tmp = NULL;
binlen = binlen;
index = index;
tmp = tmp;
if (desc == NULL || ev == NULL || ev->size < 1) {
edtk_debug("%s: bad arg(s)", __FUNCTION__);
return;
}
if (! EV_GET_CHAR(ev, &cmd, &p, &q)) {
edtk_debug("%s: empty command", __FUNCTION__);
reply_error(desc, EINVAL);
}
if ((c = sys_alloc(sizeof(callstate_t))) == NULL) {
reply_error(desc, ENOMEM);
return;
}
c->cmd = cmd;
c->key = NULL;
c->free = sys_free;
c->xid = 0; /* XXX unused right now */
c->o.__expect = 1; /* Default is that expectation is always met */
edtk_debug("%s: my threadid = %lx, cmd = %d", __FUNCTION__, pthread_self(), cmd);
switch (cmd) {
case S1_DEBUG:
EV_GET_UINT32(ev, &edtk_debug_flag, &p, &q);
reply_ok_num(desc, edtk_debug_flag); /* Immediate reply */
sys_free(c);
c = NULL;
break;
case S1_NULL:
c->invoke = invoke_s1_null;
break;
case S1_OPEN:
c->invoke = invoke_s1_open;
EV_GET_UINT32(ev, &binlen, &p, &q);
c->i.filename = (char *) EV_GETPOS(ev, p, q);
if (edtk_ev_forward_N(ev, binlen, &p, &q, 1) < 0) {
goto error;
}
EV_GET_UINT32(ev, &c->i.flags, &p, &q);
break;
case S1_GETFD:
c->invoke = invoke_s1_getfd;
EV_GET_UINT32(ev, &index, &p, &q);
if (index == -1 && 0 == 1) {
edtk_debug("%s: valmap fd index %d = default value 0x%lx", __FUNCTION__, index, -1);
c->i.fd = -1;
c->i.__valmap_fd_index = -1;
} else if (desc->valmap_fd[index] == -1) {
goto error;
} else {
edtk_debug("%s: valmap fd index %d = 0x%lx", __FUNCTION__, index, desc->valmap_fd[index]);
c->i.fd = desc->valmap_fd[index];
c->i.__valmap_fd_index = index;
}
break;
case S1_SENDFD:
c->invoke = invoke_s1_sendfd;
EV_GET_UINT32(ev, &c->i.unixdom_fd, &p, &q);
EV_GET_UINT32(ev, &c->i.fd_to_be_sent, &p, &q);
break;
case S1_RECEIVEFD:
c->invoke = invoke_s1_receivefd;
EV_GET_UINT32(ev, &c->i.unixdom_fd, &p, &q);
break;
case S1_CLOSE:
c->invoke = invoke_s1_close;
EV_GET_UINT32(ev, &index, &p, &q);
if (index == -1 && 0 == 1) {
edtk_debug("%s: valmap fd index %d = default value 0x%lx", __FUNCTION__, index, -1);
c->i.fd = -1;
c->i.__valmap_fd_index = -1;
} else if (desc->valmap_fd[index] == -1) {
goto error;
} else {
edtk_debug("%s: valmap fd index %d = 0x%lx", __FUNCTION__, index, desc->valmap_fd[index]);
c->i.fd = desc->valmap_fd[index];
c->i.__valmap_fd_index = index;
}
break;
case S1_WRITE:
c->invoke = invoke_s1_write;
EV_GET_UINT32(ev, &index, &p, &q);
if (index == -1 && 0 == 1) {
edtk_debug("%s: valmap fd index %d = default value 0x%lx", __FUNCTION__, index, -1);
c->i.fd = -1;
c->i.__valmap_fd_index = -1;
} else if (desc->valmap_fd[index] == -1) {
goto error;
} else {
edtk_debug("%s: valmap fd index %d = 0x%lx", __FUNCTION__, index, desc->valmap_fd[index]);
c->i.fd = desc->valmap_fd[index];
c->i.__valmap_fd_index = index;
}
EV_GET_UINT32(ev, &binlen, &p, &q);
c->i.__stash[0] = binlen;
c->i.ptr = (char *) EV_GETPOS(ev, p, q);
if (edtk_ev_forward_N(ev, binlen, &p, &q, 1) < 0) {
goto error;
}
break;
case S1_READ:
c->invoke = invoke_s1_read;
EV_GET_UINT32(ev, &index, &p, &q);
if (index == -1 && 0 == 1) {
edtk_debug("%s: valmap fd index %d = default value 0x%lx", __FUNCTION__, index, -1);
c->i.fd = -1;
c->i.__valmap_fd_index = -1;
} else if (desc->valmap_fd[index] == -1) {
goto error;
} else {
edtk_debug("%s: valmap fd index %d = 0x%lx", __FUNCTION__, index, desc->valmap_fd[index]);
c->i.fd = desc->valmap_fd[index];
c->i.__valmap_fd_index = index;
}
EV_GET_UINT32(ev, &c->i.size, &p, &q);
/* <hack place="post-deserialize" type="verbatim"> */
edtk_debug("XXX c->i.size = %d\r\n", c->i.size);
if ((c->i.ptr = (char *) edtk_driver_alloc_wrapper(c->i.size)) == NULL) {
goto error;
}
/* </hack --place="post-deserialize" type="verbatim"--> */
break;
default:
edtk_debug("%s: invalid command %d", __FUNCTION__, cmd);
goto error;
break;
}
if (c != NULL) {
if (do_async_call) {
driver_async(desc->port, c->key, c->invoke, c, c->free);
} else {
/*
** Execute the bottom half right away, then send the result.
*/
(*(c->invoke))((void *) c);
s1_ready_async((ErlDrvData) desc, (ErlDrvThreadData) c);
/*
** c is already freed for us by s1_ready_async()
*/
}
}
return;
error:
if (c != NULL) {
sys_free(c);
}
reply_error_atom(desc, am_badarg);
}
static void
s1_ready_async(ErlDrvData drv_data, ErlDrvThreadData thread_data)
{
descriptor_t *desc = (descriptor_t *) drv_data;
callstate_t *c = (callstate_t *) thread_data;
int bytes, offset, i;
char *p = NULL;
unsigned long index = 0;
p = p;
bytes = bytes;
offset = offset;
i = i;
index = index;
edtk_debug("%s: cmd = %d", __FUNCTION__, c->cmd);
if (c == NULL) {
edtk_debug("%s: c == NULL", __FUNCTION__);
return;
}
switch (c->cmd) {
case S1_NULL:
reply_ok(desc);
break;
case S1_OPEN:
if (! c->o.__expect) {
reply_error(desc, c->o.__expect_errval);
break;
}
if (find_unused_fd_index(desc, &index) < 0) {
reply_error(desc, ENOMEM);
} else {
desc->valmap_fd[index] = c->o.ret_int;
reply_ok_valmap(desc, am_valmap_fd, index);
}
break;
case S1_GETFD:
reply_ok_num(desc, c->o.ret_int);
break;
case S1_SENDFD:
if (c->o.__expect) {
reply_ok_num(desc, c->o.ret_int_t);
} else {
reply_error(desc, c->o.__expect_errval);
}
break;
case S1_RECEIVEFD:
if (c->o.__expect) {
reply_ok_num(desc, c->o.ret_int_t);
} else {
reply_error(desc, c->o.__expect_errval);
}
break;
case S1_CLOSE:
if (! c->o.__expect) {
reply_error(desc, c->o.__expect_errval);
break;
}
cleanup_valmap_fd_index(desc, c->i.__valmap_fd_index, 0);
reply_ok_num(desc, c->o.ret_int);
break;
case S1_WRITE:
reply_ok_num(desc, c->o.ret_ssize_t);
break;
case S1_READ:
reply_xtra_1_ptr_ssize_t(desc, c);
break;
default:
edtk_debug("%s: bogus command, should never happen", __FUNCTION__);
break;
}
sys_free(c);
}
static void
invoke_s1_null(void *data)
{
callstate_t *c = (callstate_t *) data;
c = c;
edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
null(
);
edtk_debug("%s: threadid = %lx done", __FUNCTION__, pthread_self());
}
static void
invoke_s1_open(void *data)
{
callstate_t *c = (callstate_t *) data;
c = c;
edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
c->o.ret_int = my_open(
c->i.filename,
c->i.flags
);
if (c->o.ret_int >= 0) {
c->o.__expect = 1;
} else {
c->o.__expect = 0;
c->o.__expect_errval = errno;
/* Danger! Do not put debugging statement before saving error val! */
edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__, pthread_self());
}
edtk_debug("%s: threadid = %lx done", __FUNCTION__, pthread_self());
}
static void
invoke_s1_getfd(void *data)
{
callstate_t *c = (callstate_t *) data;
c = c;
edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
c->o.ret_int = my_getfd(
c->i.fd
);
edtk_debug("%s: threadid = %lx done", __FUNCTION__, pthread_self());
}
static void
invoke_s1_sendfd(void *data)
{
callstate_t *c = (callstate_t *) data;
c = c;
edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
c->o.ret_int_t = my_sendfd(
c->i.unixdom_fd,
c->i.fd_to_be_sent
);
if (c->o.ret_int_t == 0) {
c->o.__expect = 1;
} else {
c->o.__expect = 0;
c->o.__expect_errval = errno;
/* Danger! Do not put debugging statement before saving error val! */
edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__, pthread_self());
}
edtk_debug("%s: threadid = %lx done", __FUNCTION__, pthread_self());
}
static void
invoke_s1_receivefd(void *data)
{
callstate_t *c = (callstate_t *) data;
c = c;
edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
c->o.ret_int_t = my_receivefd(
c->i.unixdom_fd
);
if (c->o.ret_int_t >= 0) {
c->o.__expect = 1;
} else {
c->o.__expect = 0;
c->o.__expect_errval = errno;
/* Danger! Do not put debugging statement before saving error val! */
edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__, pthread_self());
}
edtk_debug("%s: threadid = %lx done", __FUNCTION__, pthread_self());
}
static void
invoke_s1_close(void *data)
{
callstate_t *c = (callstate_t *) data;
c = c;
edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
c->o.ret_int = close(
c->i.fd
);
if (c->o.ret_int == 0) {
c->o.__expect = 1;
} else {
c->o.__expect = 0;
c->o.__expect_errval = errno;
/* Danger! Do not put debugging statement before saving error val! */
edtk_debug("%s: threadid = %lx expectation failed!", __FUNCTION__, pthread_self());
}
edtk_debug("%s: threadid = %lx done", __FUNCTION__, pthread_self());
}
static void
invoke_s1_write(void *data)
{
callstate_t *c = (callstate_t *) data;
c = c;
edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
c->o.ret_ssize_t = write(
c->i.fd,
c->i.ptr,
c->i.__stash[0]
);
edtk_debug("%s: threadid = %lx done", __FUNCTION__, pthread_self());
}
static void
invoke_s1_read(void *data)
{
callstate_t *c = (callstate_t *) data;
c = c;
edtk_debug("%s: threadid = %lx", __FUNCTION__, pthread_self());
c->o.ret_ssize_t = read(
c->i.fd,
c->i.ptr,
c->i.size
);
edtk_debug("%s: threadid = %lx done", __FUNCTION__, pthread_self());
}
static int
reply_ok(descriptor_t *desc)
{
ErlDrvTermData msg[24];
int i = 0;
int res;
i = LOAD_PORT(msg, i, driver_mk_port(desc->port));
i = LOAD_ATOM(msg, i, am_ok);
i = LOAD_TUPLE(msg, i, 2);
edtk_debug("reply_ok: i = %d", i);
res = driver_output_term(desc->port, msg, i);
edtk_debug("reply_ok: res = %d", res);
return res;
}
static int
reply_ok_num(descriptor_t *desc, unsigned long num)
{
ErlDrvTermData msg[24];
int i = 0;
int res;
i = LOAD_PORT(msg, i, driver_mk_port(desc->port));
i = LOAD_ATOM(msg, i, am_ok);
i = LOAD_INT(msg, i, num);
i = LOAD_TUPLE(msg, i, 3);
edtk_debug("%s: i = %d, num = %lu", __FUNCTION__, i, num);
res = driver_output_term(desc->port, msg, i);
edtk_debug("%s: res = %d", __FUNCTION__, res);
return res;
}
static int
reply_ok_binary(descriptor_t *desc, char *ptr, int beg_offset, int length)
{
ErlDrvTermData msg[24];
int i = 0;
int res;
i = LOAD_PORT(msg, i, driver_mk_port(desc->port));
i = LOAD_ATOM(msg, i, am_ok);
i = LOAD_BINARY(msg, i, edtk_alloced_ptr2ErlDrvBinary(ptr),
beg_offset, length);
i = LOAD_TUPLE(msg, i, 3);
edtk_debug("%s: i = %d, ptr = 0x%lx, start = %d, end = %d",
__FUNCTION__, i, ptr, beg_offset, length);
res = driver_output_term(desc->port, msg, i);
/* driver_output_term() incrs refc, and we're done, so decr refc */
/*
** We _know_ that "ptr" points to memory allocated by
** edtk_driver_alloc_wrapper(), so edtk_alloced_ptr2ErlDrvBinary()
** is safe in this case. If it weren't safe, then the binary
** must be returned by an xtra_return, which means we
** reply_ok_binary()) are never called!
*/
driver_free_binary(edtk_alloced_ptr2ErlDrvBinary(ptr));
edtk_debug("%s: res = %d", __FUNCTION__, res);
return res;
}
static int
reply_ok_valmap(descriptor_t *desc, ErlDrvTermData valmap_atom,
unsigned long valmap_index)
{
ErlDrvTermData msg[15];
int i = 0;
int res;
i = LOAD_PORT(msg, i, driver_mk_port(desc->port));
i = LOAD_ATOM(msg, i, am_ok);
i = LOAD_ATOM(msg, i, valmap_atom);
i = LOAD_INT(msg, i, valmap_index);
i = LOAD_TUPLE(msg, i, 2);
i = LOAD_TUPLE(msg, i, 3);
edtk_debug("reply_ok_valmap: i = %d", i);
res = driver_output_term(desc->port, msg, i);
edtk_debug("reply_ok_valmap: res = %d", res);
return res;
}
static int
reply_error(descriptor_t *desc, int errnum)
{
ErlDrvTermData msg[24];
int i = 0;
int res;
edtk_debug("reply_error: errnum = %d", errnum);
i = LOAD_PORT(msg, i, driver_mk_port(desc->port));
i = LOAD_ATOM(msg, i, am_error);
i = LOAD_INT(msg, i, errnum);
i = LOAD_TUPLE(msg, i, 3);
edtk_debug("reply_error: i = %d", i);
res = driver_output_term(desc->port, msg, i);
edtk_debug("reply_error: res = %d", res);
return res;
}
static int
reply_error_atom(descriptor_t *desc, ErlDrvTermData atom)
{
ErlDrvTermData msg[24];
int i = 0;
int res;
i = LOAD_PORT(msg, i, driver_mk_port(desc->port));
i = LOAD_ATOM(msg, i, am_error);
i = LOAD_ATOM(msg, i, atom);
i = LOAD_TUPLE(msg, i, 3);
edtk_debug("%s: i = %d", __FUNCTION__, i);
res = driver_output_term(desc->port, msg, i);
edtk_debug("%s: res = %d", __FUNCTION__, res);
return res;
}
#if 0 /* XXX These are unused right now */
static int
reply_tag_ok(descriptor_t *desc, unsigned short tag)
{
ErlDrvTermData msg[24];
int i = 0;
int res;
i = LOAD_PORT(msg, i, driver_mk_port(desc->port));
i = LOAD_INT(msg, i, tag);
i = LOAD_ATOM(msg, i, am_ok);
i = LOAD_TUPLE(msg, i, 3);
edtk_debug("reply_ok: i = %d", i);
res = driver_output_term(desc->port, msg, i);
edtk_debug("reply_ok: res = %d", res);
return res;
}
static int
reply_tag_error(descriptor_t *desc, unsigned short tag, int errnum)
{
ErlDrvTermData msg[24];
int i = 0;
int res;
edtk_debug("reply_error: errnum = %d", errnum);
i = LOAD_PORT(msg, i, driver_mk_port(desc->port));
i = LOAD_INT(msg, i, tag);
i = LOAD_INT(msg, i, errnum);
i = LOAD_ATOM(msg, i, am_error);
i = LOAD_TUPLE(msg, i, 4);
edtk_debug("reply_error: i = %d", i);
res = driver_output_term(desc->port, msg, i);
edtk_debug("reply_error: res = %d", res);
return res;
}
#endif /* 0 */
static int
reply_xtra_1_ptr_ssize_t(descriptor_t *desc, callstate_t *c)
{
ErlDrvTermData msg[MAX_RETURN_TERMS];
int msgcount = 0;
int res;
int members = 0;
char *tmp = NULL;
int i;
ErlDrvBinary *tmpbin = NULL;
tmp = tmp; tmpbin = tmpbin;
desc->num_tofree = 0;
msgcount = LOAD_PORT(msg, msgcount, driver_mk_port(desc->port));
members = 2; /* members will be 2 very shortly: Port & ok|error */
if (c->o.__expect) {
msgcount = LOAD_ATOM(msg, msgcount, am_ok);
{
int members = 0;
tmpbin = edtk_alloced_ptr2ErlDrvBinary(c->i.ptr);
msgcount = LOAD_BINARY(msg, msgcount, tmpbin, 0, c->o.ret_ssize_t);
/* driver_output_term() incrs refc, and we're done, so decr refc LATER */
desc->tofree[desc->num_tofree++] = tmpbin;
members++;
msgcount = LOAD_TUPLE(msg, msgcount, members);
}
} else {
msgcount = LOAD_ATOM(msg, msgcount, am_error);
{
int members = 0;
msgcount = LOAD_TUPLE(msg, msgcount, members);
}
}
msgcount = LOAD_TUPLE(msg, msgcount, 3);
edtk_debug("reply_xtra_1_ptr_ssize_t: i = %d", msgcount);
res = driver_output_term(desc->port, msg, msgcount);
edtk_debug("reply_xtra_1_ptr_ssize_t: res = %d", res);
if (res < 0) {
fprintf(stderr, "\r\n\r\nreply_xtra_1_ptr_ssize_t: driver_output_term() failed! This should never happen!\r\n\r\n");
}
for (i = 0; i < desc->num_tofree; i++) {
driver_free_binary(desc->tofree[i]);
}
return res;
}
static int
find_unused_fd_index(descriptor_t *desc, unsigned long *index_p)
{
int i;
for (i = 0; i < 32; i++) {
if (desc->valmap_fd[i] == -1) {
*index_p = i;
return 0;
}
}
return -1;
}
static void
cleanup_valmap_fd_index(descriptor_t *desc, int i, int do_cleanup_func)
{
edtk_debug("%s: i = %d, do_cleanup_func = %d", __FUNCTION__, i, do_cleanup_func);
if (do_cleanup_func) {
edtk_debug("%s: calling func close", __FUNCTION__);
close(desc->valmap_fd[i]);
}
desc->valmap_fd[i] = -1;
}
static void
cleanup_valmap_fd_all(descriptor_t *desc, int do_cleanup_func)
{
int i;
edtk_debug("%s: do_cleanup_func = %d", __FUNCTION__, do_cleanup_func);
for (i = 0; i < 32; i++) {
cleanup_valmap_fd_index(desc, i, do_cleanup_func);
}
}
Something went wrong with that request. Please try again.