The unified diff between revisions [76aea49e..] and [adff2b70..] is displayed below. It can also be downloaded as a raw diff.

This diff has been restricted to the following files: 'src/lsi/cmdsocket.c'

#
# old_revision [76aea49e8393c839b573eaac31eb8e2fb218d2d6]
# new_revision [adff2b70cc1870df9f9b4d736b855dffae74eca2]
#
# add_file "src/lsi/cmdsocket.c"
#  content [cd7a18effae96a82e01bc4931fca5a77fdfdbcdb]
#
============================================================
--- /dev/null	
+++ src/lsi/cmdsocket.c	cd7a18effae96a82e01bc4931fca5a77fdfdbcdb
@@ -0,0 +1,232 @@
+/* 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)-1);
+
+	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)) {
+		/* The ack gets sent by the script */
+	} 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 */
+		}
+	}
+}
+
+/*
+ * Returns offset to restart at. If off == len, then we have finished.
+ * If the return value is the same as off passed in, then the caller
+ * should sleep.
+ */
+int cmdsocket_write(char *buffer, int len, int off)
+{
+//	printf("cmdsocket_write called with %p, %d, %d\n", buffer, len, off);
+	if (!cmdsocket_initialised)
+		return 0;
+	if (!cmd_active)
+		return 0;
+
+	while (off < len) {
+		int r;
+		r = write(cmd_active, buffer + off, len - off);
+		if (r == -1) {
+			if (errno == EAGAIN)
+				return off;
+			warn("error writing packet");
+		}
+		if (r == 0)
+			return off;
+		off += r;
+	}
+	return off;
+}