The unified diff between revisions [76aea49e..] and [8583f573..] 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 [8583f573519b60d2a4dfb35aa4ec8079f05b88c1] # # 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; +}