Browse Source

cmdsocket plugin to allow simple commands to be sent over the network

master
Gavan Fantom 17 years ago
parent
commit
7f6e40716b
  1. 3
      src/lsc/codegen.c
  2. 6
      src/lsc/lexer.l
  3. 6
      src/lsi/Makefile
  4. 4
      src/lsi/abi.h
  5. 4
      src/lsi/abispec
  6. 204
      src/lsi/cmdsocket.c
  7. 8
      src/lsi/cmdsocket.h
  8. 1
      src/lsi/mouse.c
  9. 2
      src/lsi/plugins.c
  10. 102
      src/lsi/vm.c
  11. 8
      src/lsi/vm.h

3
src/lsc/codegen.c

@ -140,7 +140,7 @@ void output_functions_action(struct hashentry *ptr)
pad = (4 - (len % 4)) % 4; pad = (4 - (len % 4)) % 4;
output_int(len+pad); output_int(len+pad);
output_int(0); /* type */ output_int(0); /* type */
output_int(get_label(ptr->value) + 8); output_int(get_label(ptr->value) + 28);
output_int(0); /* nargs */ output_int(0); /* nargs */
output_string(ptr->name); output_string(ptr->name);
output_byte(0); /* terminator */ output_byte(0); /* terminator */
@ -1267,6 +1267,7 @@ void output_code(void)
if (!lookup_constant_string(x, &abiver)) \ if (!lookup_constant_string(x, &abiver)) \
printf("%s not defined\n", x); \ printf("%s not defined\n", x); \
output_int(abiver); \ output_int(abiver); \
printf("ABIVERSION(%s) = %x\n", x, abiver); \
} while (0) } while (0)
pc = (pc + 3) & ~3; /* Align table */ pc = (pc + 3) & ~3; /* Align table */

6
src/lsc/lexer.l

@ -105,8 +105,10 @@ return return TOKRETURN;
[0-9]+ yylval.Tinteger = atoi(yytext); return NUMBER; [0-9]+ yylval.Tinteger = atoi(yytext); return NUMBER;
-[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; /* Cater for the possibility that things might be signed or
-0x[0-9]+ yylval.Tinteger = strtol(yytext+2, (char **)NULL, 16); return NUMBER; 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;
-[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; [_a-zA-Z0-9]+ yylval.Tstring = strdup(yytext); return IDENTIFIER;

6
src/lsi/Makefile

@ -2,8 +2,10 @@
PREFIX?= /usr/local PREFIX?= /usr/local
OBJS= main.o vm.o plugins.o dmx.o midi.o beatdetect.o fft.o map3d.o mouse.o 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 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 OBJS+= abi.o
SRCS+= abi.c SRCS+= abi.c

4
src/lsi/abi.h

@ -44,3 +44,7 @@ int vm_intfn_sin(void);
int vm_intfn_cos(void); int vm_intfn_cos(void);
int vm_intfn_random(void); int vm_intfn_random(void);
int vm_intfn_mouse_read(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);

4
src/lsi/abispec

@ -33,6 +33,10 @@ function sin
function cos function cos
function random function random
function mouse_read 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 * The ABI should be identified by a SHA1 hash of this file

204
src/lsi/cmdsocket.c

@ -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

@ -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 *);

1
src/lsi/mouse.c

@ -55,6 +55,7 @@ int mouse_init(void)
mouse_x = 0; mouse_x = 0;
mouse_y = 0; mouse_y = 0;
mouse_z = 0; mouse_z = 0;
mouse_bytes = 0;
mouse_fd = open(MOUSEDEVICE, O_RDONLY); mouse_fd = open(MOUSEDEVICE, O_RDONLY);
if (mouse_fd < 0) { if (mouse_fd < 0) {

2
src/lsi/plugins.c

@ -11,12 +11,14 @@
#include "dmx.h" #include "dmx.h"
#include "beatdetect.h" #include "beatdetect.h"
#include "mouse.h" #include "mouse.h"
#include "cmdsocket.h"
struct plugin plugins_table[] = { struct plugin plugins_table[] = {
{"midi", midi_init, midi_close, 0}, {"midi", midi_init, midi_close, 0},
{"dmx", dmx_init, dmx_close, 0}, {"dmx", dmx_init, dmx_close, 0},
{"beatdetect", beatdetect_init, beatdetect_close, 0}, {"beatdetect", beatdetect_init, beatdetect_close, 0},
{"mouse", mouse_init, mouse_close, 0}, {"mouse", mouse_init, mouse_close, 0},
{"cmdsocket", cmdsocket_init, cmdsocket_close, 0},
}; };
int nplugins = (sizeof(plugins_table) / sizeof(struct plugin)); int nplugins = (sizeof(plugins_table) / sizeof(struct plugin));

102
src/lsi/vm.c

@ -11,6 +11,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <math.h> #include <math.h>
#include <stdarg.h>
#include "vm.h" #include "vm.h"
#include "code.h" #include "code.h"
@ -21,6 +22,7 @@
#include "beatdetect.h" #include "beatdetect.h"
#include "map3d.h" #include "map3d.h"
#include "mouse.h" #include "mouse.h"
#include "cmdsocket.h"
#define DEBUG 0 #define DEBUG 0
@ -41,6 +43,9 @@ struct vm_thread {
#define ARRAYBLOCKSIZE 512 #define ARRAYBLOCKSIZE 512
#define SLEEPTIME_SEC 60
#define SLEEPTIME_NSEC 0
struct pollfd vm_pollfd[VM_MAXPOLLFD]; struct pollfd vm_pollfd[VM_MAXPOLLFD];
int vm_pollfdqueue[VM_MAXPOLLFD]; int vm_pollfdqueue[VM_MAXPOLLFD];
@ -55,6 +60,7 @@ struct vm_thread *vm_current = NULL;
instr *vm_codearea = NULL; instr *vm_codearea = NULL;
size_t vm_codesize = 0; size_t vm_codesize = 0;
int vm_threads = 0;
struct hashentry *fnhash[HASHSIZE]; struct hashentry *fnhash[HASHSIZE];
struct hashentry *globhash[HASHSIZE]; struct hashentry *globhash[HASHSIZE];
@ -418,6 +424,46 @@ int vm_intfn_mouse_read(void)
return 0; 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) int vm_intfn_beatdetect_read(void)
{ {
if (!beatdetect_read()) { if (!beatdetect_read()) {
@ -570,6 +616,7 @@ void vm_init(void)
vm_npollfds = 0; vm_npollfds = 0;
vm_caughtsignal = 0; vm_caughtsignal = 0;
signal(SIGIO, vm_sighandler); signal(SIGIO, vm_sighandler);
signal(SIGPIPE, SIG_IGN);
} }
void vm_load_file(char *filename) void vm_load_file(char *filename)
@ -673,10 +720,11 @@ void vm_queue(struct vm_thread *thread, int queue)
vm_queues[queue] = thread; vm_queues[queue] = thread;
} }
int vm_spawn(char *fn) int vm_spawn_args(char *fn, int n, ...)
{ {
struct vm_thread *newt; struct vm_thread *newt;
struct hashentry *ptr; struct hashentry *ptr;
va_list ap;
ptr = hash_lookup(fnhash, fn, 0); ptr = hash_lookup(fnhash, fn, 0);
if (ptr == NULL) { if (ptr == NULL) {
@ -705,6 +753,12 @@ int vm_spawn(char *fn)
/* Push return address here, to point to some special thread exit /* Push return address here, to point to some special thread exit
routine */ 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 value */
stack_push(newt, 0); /* Return address */ stack_push(newt, 0); /* Return address */
@ -712,15 +766,26 @@ int vm_spawn(char *fn)
newt->prev = NULL; newt->prev = NULL;
newt->queue = VM_NOQUEUE; newt->queue = VM_NOQUEUE;
vm_queue(newt, VM_RUNQ); vm_queue(newt, VM_RUNQ);
vm_threads++;
return 1; return 1;
} }
int vm_spawn(char *fn)
{
return vm_spawn_args(fn, 0);
}
void vm_destroy(struct vm_thread *thread) void vm_destroy(struct vm_thread *thread)
{ {
vm_unqueue(thread); vm_unqueue(thread);
free(thread->stackbase); free(thread->stackbase);
free(thread); free(thread);
vm_threads--;
if (vm_threads == 0) {
printf("No threads left\n");
exit(0);
}
} }
int vm_runnable(struct vm_thread *thread) int vm_runnable(struct vm_thread *thread)
@ -757,18 +822,19 @@ void vm_sched(void)
struct timespec ts; struct timespec ts;
int rv; 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"); // printf("No runnable thread - sleeping\n");
gettimeofday(&tv, NULL); if (vm_queues[VM_TIMEQ]) {
timersub(&vm_queues[VM_TIMEQ]->time, &tv, &tv); gettimeofday(&tv, NULL);
if ((tv.tv_sec < 0) || (tv.tv_usec < 0)) { timersub(&vm_queues[VM_TIMEQ]->time, &tv, &tv);
tv.tv_sec = 0; if ((tv.tv_sec < 0) || (tv.tv_usec < 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); // nanosleep(&ts, NULL);
rv = pollts(vm_pollfd, vm_npollfds, &ts, NULL); rv = pollts(vm_pollfd, vm_npollfds, &ts, NULL);
if ((rv == -1) && (errno != EINTR)) 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); 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) void stack_push(struct vm_thread *thread, stkentry e)
{ {
thread->sp++; thread->sp++;

8
src/lsi/vm.h

@ -3,8 +3,11 @@
void vm_init(void); void vm_init(void);
void vm_load(char *); void vm_load(char *);
int vm_spawn(char *); int vm_spawn(char *);
int vm_spawn_args(char *, int, ...);
void vm_run(void); void vm_run(void);
void vm_register_signal_fd(int /* fd */, int /* queue */); 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_MAXQUEUES 512
#define VM_RUNQ 0 #define VM_RUNQ 0
@ -13,8 +16,9 @@ void vm_register_signal_fd(int /* fd */, int /* queue */);
#define VM_MOUSEQ 6 #define VM_MOUSEQ 6
#define VM_BEATQ 7 #define VM_BEATQ 7
#define VM_MIDIQ 8 #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) #define VM_NOQUEUE (-1)

Loading…
Cancel
Save