/* cmdsocket.c */ #include #include #include #include #include #include #include #include #include #include #include #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; }