#include #include #include #include #include #define LOG_MODULE "server" #include "logger/logger.h" #include "string.h" #define PORT 3456 #include "server/ws_key.c" #include "server/comms.c" mqd_t logging, tx, rx; int handle_client(int client); int main(void) { logging = mq_open("/logs", O_WRONLY); tx = mq_open("/server_to_engine", O_WRONLY); rx = mq_open("/engine_to_server", O_RDONLY); int server_fd = socket(AF_INET, SOCK_STREAM, 0); int opt = 1; setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); struct sockaddr_in addr = { .sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY, .sin_port = htons(PORT) }; if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); return 1; } if (listen(server_fd, 16) < 0) { perror("listen"); return 1; } log_infof("Listening on %d", PORT); // https://websocket.org/guides/websocket-protocol/ while(1) { int client = accept(server_fd, NULL, NULL); if (client < 0) continue; char req[4096]; int n = recv(client, req, sizeof(req) - 1, 0); if (n <= 0) { log_infof("Client close"); close(client); continue; } req[n] = 0; char *key = find_websocket_key(req); if (!key) { close(client); continue; } char accept_key[128]; websocket_accept_key(key, accept_key); char response[512]; snprintf( response, sizeof(response), "HTTP/1.1 101 Switching Protocols\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Accept: %s\r\n" "\r\n", accept_key ); send(client, response, strlen(response), 0); if (fork() == 0) { log_infof("{%d} WebSocket connected", client); while(1) { if (handle_client(client)) continue; else break; } log_infof("{%d} WebSocket disconnected", client); close(client); } } } int handle_client(int client) { unsigned char hdr[2]; int recvn; if ((recvn = recv(client, hdr, 2, MSG_WAITALL)) != 2) { if (recvn == -1) { char buf[256]; if (strerror_r(errno, buf, sizeof(buf)) == 0) { log_warnf("recv: %s", buf); } } log_warnf("{%d} recv close %d", client, recvn); return 0; } unsigned opcode = hdr[0] & 0x0F; unsigned len = hdr[1] & 0x7F; log_infof( "{%d} opcode=%u len=%u masked=%u", client, opcode, hdr[1] & 0x7F, !!(hdr[1] & 0x80) ); if (opcode == 0x8) { unsigned char close_frame[2] = {0x88, 0x00}; send(client, close_frame, 2, 0); log_warnf("{%d} opcode 0x8 close", client); return 0; } if (opcode == 0x9) { unsigned char pong[2] = {0x8A, 0x00}; send(client, pong, 2, 0); return 1; } unsigned char mask[4]; recv(client, mask, 4, MSG_WAITALL); unsigned char payload[126]; recv(client, payload, len, MSG_WAITALL); for (unsigned i = 0; i < len; i++) payload[i] ^= mask[i % 4]; payload[len] = 0; char* payload_ptr = (char*)payload; struct strs response = handle_input(logging, tx, rx, payload_ptr, len); unsigned char out[1024]; out[0] = 0x81; int shift; for (int i = 0; i < response.count; i++) { struct str item = response.data[i]; assert(item.len <= 125); log_infof("Replying %d: %.*s", client, item.len, item.msg) out[1] = item.len; shift = 2; memcpy(out + 2, item.msg, item.len); send(client, out, item.len + 2, 0); } log_infof("Replying %d: END-TRANSMISSION", client) char end_transmission[] = "END-TRANSMISSION"; int n = strlen(end_transmission); out[1] = n; memcpy(out + 2, end_transmission, n); send(client, out, n + 2, 0); return 1; }