You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
4.1 KiB
172 lines
4.1 KiB
3 years ago
|
#include "e_system.h"
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
void (*func) (void *data, const char *params);
|
||
|
void *data;
|
||
|
} Handler;
|
||
|
|
||
|
static Eina_Hash *_cmd_handlers = NULL;
|
||
|
static Ecore_Fd_Handler *_fdh_in = NULL;
|
||
|
|
||
|
//// note: commands are of the form:
|
||
|
// [ 24 bytes] command string including nul byte terminator and 0 padding
|
||
|
// [ 4 bytes] payload size (max size 2gb)
|
||
|
// [ N bytes] payload data (0 or more)...
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
char cmd[24];
|
||
|
int size;
|
||
|
} Message_Head;
|
||
|
|
||
|
static Eina_Bool
|
||
|
_cb_stdio_in_read(void *data EINA_UNUSED, Ecore_Fd_Handler *fd_handler EINA_UNUSED)
|
||
|
{
|
||
|
Handler *h;
|
||
|
Message_Head head;
|
||
|
ssize_t ret;
|
||
|
|
||
|
errno = 0;
|
||
|
ret = read(0, &head, sizeof(head));
|
||
|
if (ret < 1)
|
||
|
{
|
||
|
int e = errno;
|
||
|
if ((e == EIO) || (e == EBADF) || (e == EPIPE) ||
|
||
|
(e == EINVAL) || (e == ENOSPC) ||
|
||
|
(!((e == EAGAIN) || (e == EINTR))))
|
||
|
{
|
||
|
ecore_main_loop_quit();
|
||
|
goto done;
|
||
|
}
|
||
|
goto done;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
char *buf;
|
||
|
|
||
|
if (head.size < 0)
|
||
|
{
|
||
|
ERR("Invalid message payload size (less than 0)\n");
|
||
|
abort();
|
||
|
}
|
||
|
buf = NULL;
|
||
|
if (head.size > 0)
|
||
|
{
|
||
|
buf = malloc(head.size);
|
||
|
if (!buf)
|
||
|
{
|
||
|
ERR("Out of memory for message of size %i bytes\n", head.size);
|
||
|
abort();
|
||
|
}
|
||
|
ret = read(0, buf, head.size);
|
||
|
if (ret != head.size)
|
||
|
{
|
||
|
ERR("Cannot read full message payload of %i bytes\n", head.size);
|
||
|
abort();
|
||
|
}
|
||
|
}
|
||
|
h = eina_hash_find(_cmd_handlers, head.cmd);
|
||
|
if (h)
|
||
|
{
|
||
|
if ((!buf) || ((buf) && (buf[head.size - 1] == '\0')))
|
||
|
h->func(h->data, buf);
|
||
|
}
|
||
|
free(buf);
|
||
|
}
|
||
|
done:
|
||
|
return EINA_TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
e_system_inout_init(void)
|
||
|
{
|
||
|
_cmd_handlers = eina_hash_string_superfast_new(free);
|
||
|
_fdh_in = ecore_main_fd_handler_add(0, ECORE_FD_READ,
|
||
|
_cb_stdio_in_read, NULL,
|
||
|
NULL, NULL);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
e_system_inout_shutdown(void)
|
||
|
{
|
||
|
ecore_main_fd_handler_del(_fdh_in);
|
||
|
_fdh_in = NULL;
|
||
|
eina_hash_free(_cmd_handlers);
|
||
|
_cmd_handlers = NULL;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
e_system_inout_command_register(const char *cmd, void (*func) (void *data, const char *params), void *data)
|
||
|
{
|
||
|
Handler *h = malloc(sizeof(Handler));
|
||
|
size_t len = strlen(cmd);
|
||
|
if (!h)
|
||
|
{
|
||
|
ERR("Out of memory registering command handlers\n");
|
||
|
abort();
|
||
|
}
|
||
|
if (len > 23)
|
||
|
{
|
||
|
ERR("Trying to register command of length %i (max 23)\n", (int)len);
|
||
|
abort();
|
||
|
}
|
||
|
h->func = func;
|
||
|
h->data = data;
|
||
|
eina_hash_add(_cmd_handlers, cmd, h);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
e_system_inout_command_send(const char *cmd, const char *fmt, ...)
|
||
|
{
|
||
|
char *buf = NULL, stack_buf[4096];
|
||
|
Message_Head head;
|
||
|
size_t len = strlen(cmd);
|
||
|
int printed = 0;
|
||
|
ssize_t ret;
|
||
|
va_list ap;
|
||
|
|
||
|
if (len > 23)
|
||
|
{
|
||
|
ERR("Trying to send command of length %i (max 23)\n", (int)len);
|
||
|
abort();
|
||
|
}
|
||
|
if (fmt)
|
||
|
{
|
||
|
buf = stack_buf;
|
||
|
va_start(ap, fmt);
|
||
|
printed = vsnprintf(stack_buf, sizeof(stack_buf), fmt, ap);
|
||
|
va_end(ap);
|
||
|
if ((size_t)printed >= (sizeof(stack_buf) - 1))
|
||
|
{
|
||
|
buf = malloc(printed + 1);
|
||
|
if (!buf) goto end;
|
||
|
va_start(ap, fmt);
|
||
|
printed = vsnprintf(buf, printed + 1, fmt, ap);
|
||
|
va_end(ap);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
memset(head.cmd, 0, sizeof(head.cmd));
|
||
|
memcpy(head.cmd, cmd, len);
|
||
|
if (printed > 0) head.size = printed + 1;
|
||
|
else head.size = 0;
|
||
|
ret = write(1, &head, sizeof(head));
|
||
|
if (ret != sizeof(head))
|
||
|
{
|
||
|
ERR("Write of command failed at %lli\n", (long long)ret);
|
||
|
abort();
|
||
|
}
|
||
|
if ((buf) && (head.size > 0))
|
||
|
{
|
||
|
ret = write(1, buf, head.size);
|
||
|
if (ret != (ssize_t)head.size)
|
||
|
{
|
||
|
ERR("Write of command buffer failed at %lli/%llu\n", (long long)ret, (unsigned long long)head.size);
|
||
|
abort();
|
||
|
}
|
||
|
}
|
||
|
end:
|
||
|
if (buf != stack_buf) free(buf);
|
||
|
}
|