cmdsocket plugin to allow simple commands to be sent over the network
This commit is contained in:
@@ -140,7 +140,7 @@ void output_functions_action(struct hashentry *ptr)
|
||||
pad = (4 - (len % 4)) % 4;
|
||||
output_int(len+pad);
|
||||
output_int(0); /* type */
|
||||
output_int(get_label(ptr->value) + 8);
|
||||
output_int(get_label(ptr->value) + 28);
|
||||
output_int(0); /* nargs */
|
||||
output_string(ptr->name);
|
||||
output_byte(0); /* terminator */
|
||||
@@ -1267,6 +1267,7 @@ void output_code(void)
|
||||
if (!lookup_constant_string(x, &abiver)) \
|
||||
printf("%s not defined\n", x); \
|
||||
output_int(abiver); \
|
||||
printf("ABIVERSION(%s) = %x\n", x, abiver); \
|
||||
} while (0)
|
||||
|
||||
pc = (pc + 3) & ~3; /* Align table */
|
||||
|
||||
@@ -105,8 +105,10 @@ return return TOKRETURN;
|
||||
|
||||
[0-9]+ yylval.Tinteger = atoi(yytext); return NUMBER;
|
||||
-[0-9]+ yylval.Tinteger = atoi(yytext); return NUMBER;
|
||||
0x[0-9]+ yylval.Tinteger = strtol(yytext+2, (char **)NULL, 16); return NUMBER;
|
||||
-0x[0-9]+ yylval.Tinteger = strtol(yytext+2, (char **)NULL, 16); return NUMBER;
|
||||
/* Cater for the possibility that things might be signed or
|
||||
unsigned. This is horrible and ugly, but might just work. */
|
||||
0x[0-9a-fA-F]+ yylval.Tinteger = strtoul(yytext+2, (char **)NULL, 16); return NUMBER;
|
||||
-0x[0-9a-fA-F]+ yylval.Tinteger = strtol(yytext+2, (char **)NULL, 16); return NUMBER;
|
||||
[0-9]+\.[0-9]+ yylval.Treal = atof(yytext); return REAL;
|
||||
-[0-9]+\.[0-9]+ yylval.Treal = atof(yytext); return REAL;
|
||||
[_a-zA-Z0-9]+ yylval.Tstring = strdup(yytext); return IDENTIFIER;
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
PREFIX?= /usr/local
|
||||
|
||||
OBJS= main.o vm.o plugins.o dmx.o midi.o beatdetect.o fft.o map3d.o mouse.o
|
||||
SRCS= main.c vm.c plugins.c dmx.c midi.c beatdetect.c fft.c map3d.c mouse.c
|
||||
OBJS= main.o vm.o plugins.o dmx.o midi.o beatdetect.o fft.o map3d.o mouse.o \
|
||||
cmdsocket.o
|
||||
SRCS= main.c vm.c plugins.c dmx.c midi.c beatdetect.c fft.c map3d.c mouse.c \
|
||||
cmdsocket.c
|
||||
|
||||
OBJS+= abi.o
|
||||
SRCS+= abi.c
|
||||
|
||||
@@ -44,3 +44,7 @@ int vm_intfn_sin(void);
|
||||
int vm_intfn_cos(void);
|
||||
int vm_intfn_random(void);
|
||||
int vm_intfn_mouse_read(void);
|
||||
int vm_intfn_cmdsocket_listen(void);
|
||||
int vm_intfn_cmdsocket_accept(void);
|
||||
int vm_intfn_cmdsocket_read(void);
|
||||
int vm_intfn_cmdsocket_prefix(void);
|
||||
|
||||
@@ -33,6 +33,10 @@ function sin
|
||||
function cos
|
||||
function random
|
||||
function mouse_read
|
||||
function cmdsocket_listen
|
||||
function cmdsocket_accept
|
||||
function cmdsocket_read
|
||||
function cmdsocket_prefix
|
||||
|
||||
/*
|
||||
* The ABI should be identified by a SHA1 hash of this file
|
||||
|
||||
204
src/lsi/cmdsocket.c
Normal file
204
src/lsi/cmdsocket.c
Normal file
@@ -0,0 +1,204 @@
|
||||
/* cmdsocket.c */
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <dev/wscons/wsconsio.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "vm.h"
|
||||
|
||||
#define PORT 15674
|
||||
#define CMD_MAXSIZE 1024
|
||||
#define PREFIX_MAXSIZE 1024
|
||||
|
||||
#define CMDSOCKET_BANNER "lightscript cmdsocket ready\r\n"
|
||||
|
||||
int cmd_sock = 0;
|
||||
int cmd_active = 0;
|
||||
int cmd_ignore;
|
||||
int cmd_bytes;
|
||||
int cmdsocket_initialised = 0;
|
||||
char cmd_buf[CMD_MAXSIZE];
|
||||
char cmd_prefix[PREFIX_MAXSIZE];
|
||||
|
||||
int cmdsocket_init(void)
|
||||
{
|
||||
cmdsocket_initialised = 1;
|
||||
cmd_bytes = 0;
|
||||
cmd_ignore = 0;
|
||||
cmd_prefix[0] = '\0';
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void cmdsocket_close(void)
|
||||
{
|
||||
if (cmd_active)
|
||||
close(cmd_active);
|
||||
if (cmd_sock)
|
||||
close(cmd_sock);
|
||||
cmdsocket_initialised = 0;
|
||||
}
|
||||
|
||||
void cmdsocket_prefix(char *prefix)
|
||||
{
|
||||
if (!cmdsocket_initialised)
|
||||
return;
|
||||
if (strlen(prefix) >= PREFIX_MAXSIZE-1)
|
||||
return;
|
||||
strncpy(cmd_prefix, prefix, PREFIX_MAXSIZE);
|
||||
}
|
||||
|
||||
#define ERROR(x) do { warn((x)); goto error; } while (0)
|
||||
|
||||
#define BACKLOG 0
|
||||
|
||||
int cmdsocket_listen(int port) {
|
||||
int sockopt_on = 1;
|
||||
struct sockaddr_in my_addr;
|
||||
|
||||
cmd_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (cmd_sock == -1)
|
||||
ERROR("can't open socket");
|
||||
if (setsockopt(cmd_sock, SOL_SOCKET, SO_REUSEADDR, &sockopt_on,
|
||||
sizeof(int)) == -1)
|
||||
ERROR("can't set socket options");
|
||||
memset((char *) &my_addr, 0, sizeof(my_addr));
|
||||
my_addr.sin_family = PF_INET;
|
||||
my_addr.sin_port = htons(port);
|
||||
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
if (bind(cmd_sock, (struct sockaddr *)&my_addr, sizeof(my_addr)) == -1)
|
||||
ERROR("can't bind socket");
|
||||
if (listen(cmd_sock, BACKLOG) == -1)
|
||||
ERROR("can't listen");
|
||||
vm_register_signal_fd(cmd_sock, VM_CMDLISTENQ);
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
if (cmd_sock)
|
||||
close(cmd_sock);
|
||||
cmd_sock = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int cmdsocket_accept(void) {
|
||||
struct sockaddr_in client_addr;
|
||||
socklen_t client_addr_size = sizeof(client_addr);
|
||||
int c;
|
||||
|
||||
if (!cmdsocket_initialised)
|
||||
return 0;
|
||||
if (cmd_sock == 0)
|
||||
return 0;
|
||||
|
||||
/* We only accept one active connection at a time */
|
||||
/* XXX can't just return here */
|
||||
if (cmd_active)
|
||||
return 0;
|
||||
|
||||
c = accept(cmd_sock, (struct sockaddr *)&client_addr,
|
||||
&client_addr_size);
|
||||
if (c == -1) {
|
||||
if (errno == EAGAIN)
|
||||
return 0;
|
||||
warn("Error accepting connection");
|
||||
close(cmd_sock);
|
||||
cmd_sock = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cmd_active = c;
|
||||
write(cmd_active, CMDSOCKET_BANNER, sizeof(CMDSOCKET_BANNER));
|
||||
|
||||
vm_register_signal_fd(cmd_active, VM_CMDREADQ);
|
||||
vm_wakeup(VM_CMDREADQ);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void cmd_parse(char *cmd) {
|
||||
char *sp;
|
||||
int arg = 0;
|
||||
char function[CMD_MAXSIZE + PREFIX_MAXSIZE];
|
||||
|
||||
*strchr(cmd, '\n') = '\0';
|
||||
printf("DEBUG: Received command: %s\n", cmd);
|
||||
fflush(stdout);
|
||||
|
||||
sp = strtok(cmd, " \t\r");
|
||||
sp = strtok(NULL, " \t\r");
|
||||
if (sp) {
|
||||
arg = atoi(sp);
|
||||
}
|
||||
|
||||
/* cmd_prefix is guaranteed to be terminated */
|
||||
strcpy(function, cmd_prefix);
|
||||
strncat(function, cmd, CMD_MAXSIZE);
|
||||
|
||||
printf("DEBUG: function: %s, arg %d\n", function, arg);
|
||||
fflush(stdout);
|
||||
if (vm_spawn_args(function, 1, arg)) {
|
||||
/* Write an ack here, once a proper function exists */
|
||||
} else {
|
||||
/* Write an error, if it's possible. Don't worry about
|
||||
missing characters and buffering for now, but we
|
||||
should eventually */
|
||||
write(cmd_active, "ERROR\n", strlen("ERROR\n"));
|
||||
}
|
||||
|
||||
printf("Received command: %s\n", cmd);
|
||||
}
|
||||
|
||||
int cmdsocket_read(void)
|
||||
{
|
||||
if (!cmdsocket_initialised)
|
||||
return 0;
|
||||
|
||||
while (1) {
|
||||
int rv;
|
||||
int left = sizeof(cmd_buf) - cmd_bytes;
|
||||
char *p;
|
||||
if (!cmd_active)
|
||||
return 0;
|
||||
|
||||
rv = recv(cmd_active, ((char *)&cmd_buf) + cmd_bytes, left, 0);
|
||||
if (rv == -1) {
|
||||
if (errno == EAGAIN)
|
||||
return 0;
|
||||
printf("Error reading from socket\n");
|
||||
vm_unregister_signal_fd(cmd_active);
|
||||
close(cmd_active);
|
||||
cmd_active = 0;
|
||||
vm_wakeup(VM_CMDLISTENQ);
|
||||
return 0;
|
||||
}
|
||||
if (rv == 0) {
|
||||
vm_unregister_signal_fd(cmd_active);
|
||||
close(cmd_active);
|
||||
cmd_active = 0;
|
||||
vm_wakeup(VM_CMDLISTENQ);
|
||||
return 0;
|
||||
}
|
||||
cmd_bytes += rv;
|
||||
if ((p = memchr(cmd_buf, '\n', cmd_bytes))) {
|
||||
if (!cmd_ignore)
|
||||
cmd_parse(cmd_buf);
|
||||
memmove(cmd_buf, p+1, cmd_bytes - (p - cmd_buf - 1));
|
||||
cmd_bytes = 0;
|
||||
cmd_ignore = 0;
|
||||
}
|
||||
if (cmd_bytes == sizeof(cmd_buf)) {
|
||||
cmd_bytes = 0;
|
||||
cmd_ignore = 1;
|
||||
/* Overflow */
|
||||
}
|
||||
}
|
||||
}
|
||||
8
src/lsi/cmdsocket.h
Normal file
8
src/lsi/cmdsocket.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/* cmdsocket.h */
|
||||
|
||||
int cmdsocket_init(void);
|
||||
void cmdsocket_close(void);
|
||||
int cmdsocket_listen(int port);
|
||||
int cmdsocket_accept(void);
|
||||
int cmdsocket_read(void);
|
||||
int cmdsocket_prefix(char *);
|
||||
@@ -55,6 +55,7 @@ int mouse_init(void)
|
||||
mouse_x = 0;
|
||||
mouse_y = 0;
|
||||
mouse_z = 0;
|
||||
mouse_bytes = 0;
|
||||
|
||||
mouse_fd = open(MOUSEDEVICE, O_RDONLY);
|
||||
if (mouse_fd < 0) {
|
||||
|
||||
@@ -11,12 +11,14 @@
|
||||
#include "dmx.h"
|
||||
#include "beatdetect.h"
|
||||
#include "mouse.h"
|
||||
#include "cmdsocket.h"
|
||||
|
||||
struct plugin plugins_table[] = {
|
||||
{"midi", midi_init, midi_close, 0},
|
||||
{"dmx", dmx_init, dmx_close, 0},
|
||||
{"beatdetect", beatdetect_init, beatdetect_close, 0},
|
||||
{"mouse", mouse_init, mouse_close, 0},
|
||||
{"cmdsocket", cmdsocket_init, cmdsocket_close, 0},
|
||||
};
|
||||
|
||||
int nplugins = (sizeof(plugins_table) / sizeof(struct plugin));
|
||||
|
||||
102
src/lsi/vm.c
102
src/lsi/vm.c
@@ -11,6 +11,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "vm.h"
|
||||
#include "code.h"
|
||||
@@ -21,6 +22,7 @@
|
||||
#include "beatdetect.h"
|
||||
#include "map3d.h"
|
||||
#include "mouse.h"
|
||||
#include "cmdsocket.h"
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
@@ -41,6 +43,9 @@ struct vm_thread {
|
||||
|
||||
#define ARRAYBLOCKSIZE 512
|
||||
|
||||
#define SLEEPTIME_SEC 60
|
||||
#define SLEEPTIME_NSEC 0
|
||||
|
||||
struct pollfd vm_pollfd[VM_MAXPOLLFD];
|
||||
int vm_pollfdqueue[VM_MAXPOLLFD];
|
||||
|
||||
@@ -55,6 +60,7 @@ struct vm_thread *vm_current = NULL;
|
||||
|
||||
instr *vm_codearea = NULL;
|
||||
size_t vm_codesize = 0;
|
||||
int vm_threads = 0;
|
||||
|
||||
struct hashentry *fnhash[HASHSIZE];
|
||||
struct hashentry *globhash[HASHSIZE];
|
||||
@@ -418,6 +424,46 @@ int vm_intfn_mouse_read(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vm_intfn_cmdsocket_listen(void)
|
||||
{
|
||||
stack_poke(vm_current, 0,
|
||||
cmdsocket_listen(stack_get(vm_current, 1)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vm_intfn_cmdsocket_prefix(void)
|
||||
{
|
||||
char buf[VM_STRING_MAX];
|
||||
int len = stack_get(vm_current, 1);
|
||||
|
||||
strncpy(buf, stack_getstr(vm_current, len, 1), len);
|
||||
buf[len] = '\0';
|
||||
|
||||
cmdsocket_prefix(buf);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vm_intfn_cmdsocket_accept(void)
|
||||
{
|
||||
if (!cmdsocket_accept()) {
|
||||
vm_queue(vm_current, VM_CMDLISTENQ);
|
||||
vm_current = NULL;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vm_intfn_cmdsocket_read(void)
|
||||
{
|
||||
if (!cmdsocket_read()) {
|
||||
vm_queue(vm_current, VM_CMDREADQ);
|
||||
vm_current = NULL;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vm_intfn_beatdetect_read(void)
|
||||
{
|
||||
if (!beatdetect_read()) {
|
||||
@@ -570,6 +616,7 @@ void vm_init(void)
|
||||
vm_npollfds = 0;
|
||||
vm_caughtsignal = 0;
|
||||
signal(SIGIO, vm_sighandler);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
}
|
||||
|
||||
void vm_load_file(char *filename)
|
||||
@@ -673,10 +720,11 @@ void vm_queue(struct vm_thread *thread, int queue)
|
||||
vm_queues[queue] = thread;
|
||||
}
|
||||
|
||||
int vm_spawn(char *fn)
|
||||
int vm_spawn_args(char *fn, int n, ...)
|
||||
{
|
||||
struct vm_thread *newt;
|
||||
struct hashentry *ptr;
|
||||
va_list ap;
|
||||
|
||||
ptr = hash_lookup(fnhash, fn, 0);
|
||||
if (ptr == NULL) {
|
||||
@@ -705,6 +753,12 @@ int vm_spawn(char *fn)
|
||||
/* Push return address here, to point to some special thread exit
|
||||
routine */
|
||||
|
||||
/* Push optional arguments */
|
||||
va_start(ap, n);
|
||||
while (n--)
|
||||
stack_push(newt, va_arg(ap, int));
|
||||
va_end(ap);
|
||||
|
||||
stack_push(newt, 0); /* Return value */
|
||||
stack_push(newt, 0); /* Return address */
|
||||
|
||||
@@ -712,15 +766,26 @@ int vm_spawn(char *fn)
|
||||
newt->prev = NULL;
|
||||
newt->queue = VM_NOQUEUE;
|
||||
vm_queue(newt, VM_RUNQ);
|
||||
vm_threads++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vm_spawn(char *fn)
|
||||
{
|
||||
return vm_spawn_args(fn, 0);
|
||||
}
|
||||
|
||||
void vm_destroy(struct vm_thread *thread)
|
||||
{
|
||||
vm_unqueue(thread);
|
||||
free(thread->stackbase);
|
||||
free(thread);
|
||||
vm_threads--;
|
||||
if (vm_threads == 0) {
|
||||
printf("No threads left\n");
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
int vm_runnable(struct vm_thread *thread)
|
||||
@@ -757,18 +822,19 @@ void vm_sched(void)
|
||||
struct timespec ts;
|
||||
int rv;
|
||||
|
||||
if (vm_queues[VM_TIMEQ] == NULL) {
|
||||
printf("No runnable thread, and no waiting thread\n");
|
||||
exit(0);
|
||||
}
|
||||
// printf("No runnable thread - sleeping\n");
|
||||
gettimeofday(&tv, NULL);
|
||||
timersub(&vm_queues[VM_TIMEQ]->time, &tv, &tv);
|
||||
if ((tv.tv_sec < 0) || (tv.tv_usec < 0)) {
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
if (vm_queues[VM_TIMEQ]) {
|
||||
gettimeofday(&tv, NULL);
|
||||
timersub(&vm_queues[VM_TIMEQ]->time, &tv, &tv);
|
||||
if ((tv.tv_sec < 0) || (tv.tv_usec < 0)) {
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
}
|
||||
TIMEVAL_TO_TIMESPEC(&tv, &ts);
|
||||
} else {
|
||||
ts.tv_sec = SLEEPTIME_SEC;
|
||||
ts.tv_nsec = SLEEPTIME_NSEC;
|
||||
}
|
||||
TIMEVAL_TO_TIMESPEC(&tv, &ts);
|
||||
// nanosleep(&ts, NULL);
|
||||
rv = pollts(vm_pollfd, vm_npollfds, &ts, NULL);
|
||||
if ((rv == -1) && (errno != EINTR))
|
||||
@@ -791,6 +857,20 @@ void vm_register_signal_fd(int fd, int queue)
|
||||
rv = fcntl(fd, F_SETFL, O_NONBLOCK | O_ASYNC);
|
||||
}
|
||||
|
||||
void vm_unregister_signal_fd(int fd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < vm_npollfds; i++) {
|
||||
if (fd == vm_pollfd[i].fd) {
|
||||
memmove(&vm_pollfd[i], &vm_pollfd[i+1],
|
||||
sizeof(struct pollfd) * (vm_npollfds-i-1));
|
||||
vm_npollfds--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void stack_push(struct vm_thread *thread, stkentry e)
|
||||
{
|
||||
thread->sp++;
|
||||
|
||||
@@ -3,8 +3,11 @@
|
||||
void vm_init(void);
|
||||
void vm_load(char *);
|
||||
int vm_spawn(char *);
|
||||
int vm_spawn_args(char *, int, ...);
|
||||
void vm_run(void);
|
||||
void vm_register_signal_fd(int /* fd */, int /* queue */);
|
||||
void vm_unregister_signal_fd(int /* fd */);
|
||||
void vm_wakeup(int queue);
|
||||
|
||||
#define VM_MAXQUEUES 512
|
||||
#define VM_RUNQ 0
|
||||
@@ -13,8 +16,9 @@ void vm_register_signal_fd(int /* fd */, int /* queue */);
|
||||
#define VM_MOUSEQ 6
|
||||
#define VM_BEATQ 7
|
||||
#define VM_MIDIQ 8
|
||||
#define VM_SOCKQ 9
|
||||
#define VM_CMDLISTENQ 9
|
||||
#define VM_CMDREADQ 10
|
||||
|
||||
#define VM_USERQMIN 10
|
||||
#define VM_USERQMIN 20
|
||||
#define VM_NOQUEUE (-1)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user