diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3b3e81b..731f503 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,4 +24,10 @@ add_executable(
src/smol-http-pthreads.c
)
-install(TARGETS smol smol-pthreads smol-http smol-http-pthreads DESTINATION bin)
\ No newline at end of file
+add_executable(
+ ws
+ src/ws.c
+)
+target_link_libraries(ws ssl crypto)
+
+install(TARGETS smol smol-pthreads smol-http smol-http-pthreads ws DESTINATION bin)
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 58b6efa..db4d0c5 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@ default: all
all: clean build
-build: smol smol-pthreads smol-http smol-http-pthreads
+build: smol smol-pthreads smol-http smol-http-pthreads ws
smol:
$(CC) -o $(BIN)/smol $(SRC)/smol.c -lcrypto -lssl $(CFLAGS)
@@ -23,6 +23,9 @@ smol-http:
smol-http-pthreads:
$(CC) -o $(BIN)/smol-http-pthreads $(SRC)/smol-http-pthreads.c $(CFLAGS)
+ws:
+ $(CC) -o $(BIN)/ws $(SRC)/ws.c $(CFLAGS) -lcrypto -lssl
+
clean:
if [ -d $(BIN) ]; then rm -rv $(BIN);mkdir -pv $(BIN);else mkdir -pv $(BIN);fi
@@ -32,6 +35,7 @@ install:
$(STRIP) $(PREFIX)/bin/smol-pthreads
$(STRIP) $(PREFIX)/bin/smol-http
$(STRIP) $(PREFIX)/bin/smol-http-pthreads
+ $(STRIP) $(PREFIX)/bin/ws
uninstall: remove
@@ -39,4 +43,5 @@ remove:
if [ -f $(PREFIX)/bin/smol ];then rm -v $(PREFIX)/bin/smol;fi
if [ -f $(PREFIX)/bin/smol-pthreads ];then rm -v $(PREFIX)/bin/smol-pthreads;fi
if [ -f $(PREFIX)/bin/smol-http ];then rm -v $(PREFIX)/bin/smol-http;fi
- if [ -f $(PREFIX)/bin/smol-http-pthreads ];then rm -v $(PREFIX)/bin/smol-http-pthreads;fi
\ No newline at end of file
+ if [ -f $(PREFIX)/bin/smol-http-pthreads ];then rm -v $(PREFIX)/bin/smol-http-pthreads;fi
+ if [ -f $(PREFIX)/bin/ws ];then rm -v $(PREFIX)/bin/ws;fi
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..519e41f
--- /dev/null
+++ b/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Document
+
+
+
+
+
+
\ No newline at end of file
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..29599bc
--- /dev/null
+++ b/index.js
@@ -0,0 +1,19 @@
+const uptime = document.querySelector('#time')
+const ws = new WebSocket('ws://172.16.17.21:8080');
+ws.onopen = () => {
+ ws.send('Hello Server!');
+}
+
+ws.onmessage = (e) => {
+ console.log('Received:', e.data);
+ var jsondata = JSON.parse(e.data);
+ if (jsondata.uptime.hour === '0' && jsondata.uptime.minute === '0') {
+ uptime.innerHTML = jsondata.uptime.second + "s "
+ return
+ }
+ if (jsondata.uptime.hour === '0') {
+ uptime.innerHTML = jsondata.uptime.minute + "m " + jsondata.uptime.second + "s "
+ return
+ }
+ uptime.innerHTML = jsondata.uptime.hour + "h " + jsondata.uptime.minute + "m " + jsondata.uptime.second + "s "
+}
diff --git a/meson.build b/meson.build
index e757653..c8a1fe4 100644
--- a/meson.build
+++ b/meson.build
@@ -24,4 +24,11 @@ executable(
'smol-http-pthreads',
'src/smol-http-pthreads.c',
install: true,
+)
+
+executable(
+ 'ws',
+ 'src/ws.c',
+ dependencies: deps,
+ install: true,
)
\ No newline at end of file
diff --git a/src/ws.c b/src/ws.c
new file mode 100644
index 0000000..6da747c
--- /dev/null
+++ b/src/ws.c
@@ -0,0 +1,198 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define PORT 8080
+#define BUFFER_SIZE 1024
+
+char* base64_encode(const unsigned char* input, int length) {
+ BIO *bio, *b64;
+ BUF_MEM *bufferPtr;
+
+ b64 = BIO_new(BIO_f_base64());
+ bio = BIO_new(BIO_s_mem());
+ bio = BIO_push(b64, bio);
+
+ BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
+ BIO_write(bio, input, length);
+ BIO_flush(bio);
+ BIO_get_mem_ptr(bio, &bufferPtr);
+
+ // Создаем копию данных, так как буфер BIO будет очищен
+ char *output = (char *)malloc(bufferPtr->length + 1);
+ memcpy(output, bufferPtr->data, bufferPtr->length);
+ output[bufferPtr->length] = '\0';
+
+ BIO_free_all(bio);
+ return output;
+}
+
+char* compute_accept_key(const char* client_key) {
+ char combined[256];
+ sprintf(combined, "%s%s", client_key, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
+ unsigned char sha_result[SHA_DIGEST_LENGTH];
+ SHA1((unsigned char*)combined, strlen(combined), sha_result);
+ return base64_encode(sha_result, SHA_DIGEST_LENGTH);
+}
+
+int read_fully(int socket, unsigned char* buffer, int length) {
+ int total = 0;
+ while(total < length) {
+ int readed = read(socket, buffer + total, length - total);
+ if(readed <= 0) return readed;
+ total += readed;
+ }
+ return total;
+}
+
+int main() {
+ int server_fd, client_socket;
+ struct sockaddr_in address;
+ int addrlen = sizeof(address);
+
+ if((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
+ perror("socket failed");
+ exit(EXIT_FAILURE);
+ }
+
+ int opt = 1;
+ setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+ signal(SIGPIPE, SIG_IGN);
+
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = INADDR_ANY;
+ address.sin_port = htons(PORT);
+
+ if(bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
+ perror("bind failed");
+ exit(EXIT_FAILURE);
+ }
+
+ if(listen(server_fd, 3) < 0) {
+ perror("listen");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("Server listening on port %d\n", PORT);
+
+ while(1) {
+ if((client_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
+ perror("accept");
+ continue;
+ }
+
+ printf("Client connected\n");
+ char buffer[BUFFER_SIZE] = {0};
+ int valread = read(client_socket, buffer, BUFFER_SIZE);
+
+ if(valread < 0) {
+ perror("read");
+ close(client_socket);
+ continue;
+ }
+
+ if(strstr(buffer, "Upgrade: websocket") && strstr(buffer, "Connection: Upgrade")) {
+ char* key_start = strstr(buffer, "Sec-WebSocket-Key: ");
+ if(key_start) {
+ key_start += 19;
+ char* key_end = strstr(key_start, "\r\n");
+ if(key_end) {
+ char client_key[256];
+ int key_len = key_end - key_start;
+ strncpy(client_key, key_start, key_len);
+ client_key[key_len] = '\0';
+
+ char* accept_key = compute_accept_key(client_key);
+
+ char response[512];
+ sprintf(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);
+
+ if (send(client_socket, response, strlen(response), 0) <= 0) {
+ printf("send failed\n");
+ free(accept_key);
+ continue;
+ }
+ free(accept_key);
+
+ while(1) {
+ unsigned char header[2];
+ if(read_fully(client_socket, header, 2) <= 0) break;
+
+ int opcode = header[0] & 0x0F;
+ int mask = (header[1] >> 7) & 1;
+ int length = header[1] & 0x7F;
+
+ if(length == 126) {
+ unsigned char ext_len[2];
+ read_fully(client_socket, ext_len, 2);
+ length = (ext_len[0] << 8) | ext_len[1];
+ } else if(length == 127) {
+ printf("Large frames not supported\n");
+ break;
+ }
+
+ unsigned char masking_key[4];
+ if(mask) {
+ read_fully(client_socket, masking_key, 4);
+ }
+
+ unsigned char* data = malloc(length + 1);
+ read_fully(client_socket, data, length);
+
+ if(mask) {
+ for(int i = 0; i < length; i++) {
+ data[i] ^= masking_key[i % 4];
+ }
+ }
+ data[length] = '\0';
+
+ if(opcode == 0x08) break; // Close frame
+
+ printf("Received: %s\n", data);
+
+ // Prepare response
+ while (1) {
+ char timebuffer[BUFSIZ];
+ memset(&timebuffer, '\0', BUFSIZ);
+ struct sysinfo x;
+ if (sysinfo(&x) == 0) {
+ sprintf(timebuffer,
+ "{\"uptime\":{\"hour\":\"%llu\",\"minute\":\"%llu\",\"second\":\"%llu\"}}",
+ (unsigned long long)x.uptime / 3600ULL, (unsigned long long)x.uptime / 60ULL % 60ULL, (unsigned long long)x.uptime % 60ULL);
+ }
+ printf("%s\n", timebuffer);
+ unsigned char response_header[2] = {0x81, strlen(timebuffer)};
+ if (send(client_socket, response_header, 2, 0) <= 0) {
+ printf("send failed\n");
+ break;
+ }
+ if (send(client_socket, timebuffer, strlen(timebuffer), 0) <= 0) {
+ printf("send failed\n");
+ break;
+ }
+ sleep(1);
+ }
+ free(data);
+ }
+ }
+ }
+ }
+ printf("Client disconnected\n");
+ close(client_socket);
+ }
+ close(server_fd);
+ return 0;
+}
\ No newline at end of file