added websocket smol server

This commit is contained in:
wt
2025-04-15 17:07:40 +07:00
parent afa63acf85
commit d59a7fc6b5
6 changed files with 250 additions and 3 deletions
+7 -1
View File
@@ -24,4 +24,10 @@ add_executable(
src/smol-http-pthreads.c src/smol-http-pthreads.c
) )
install(TARGETS smol smol-pthreads smol-http smol-http-pthreads DESTINATION bin) 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)
+6 -1
View File
@@ -9,7 +9,7 @@ default: all
all: clean build all: clean build
build: smol smol-pthreads smol-http smol-http-pthreads build: smol smol-pthreads smol-http smol-http-pthreads ws
smol: smol:
$(CC) -o $(BIN)/smol $(SRC)/smol.c -lcrypto -lssl $(CFLAGS) $(CC) -o $(BIN)/smol $(SRC)/smol.c -lcrypto -lssl $(CFLAGS)
@@ -23,6 +23,9 @@ smol-http:
smol-http-pthreads: smol-http-pthreads:
$(CC) -o $(BIN)/smol-http-pthreads $(SRC)/smol-http-pthreads.c $(CFLAGS) $(CC) -o $(BIN)/smol-http-pthreads $(SRC)/smol-http-pthreads.c $(CFLAGS)
ws:
$(CC) -o $(BIN)/ws $(SRC)/ws.c $(CFLAGS) -lcrypto -lssl
clean: clean:
if [ -d $(BIN) ]; then rm -rv $(BIN);mkdir -pv $(BIN);else mkdir -pv $(BIN);fi 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-pthreads
$(STRIP) $(PREFIX)/bin/smol-http $(STRIP) $(PREFIX)/bin/smol-http
$(STRIP) $(PREFIX)/bin/smol-http-pthreads $(STRIP) $(PREFIX)/bin/smol-http-pthreads
$(STRIP) $(PREFIX)/bin/ws
uninstall: remove uninstall: remove
@@ -40,3 +44,4 @@ remove:
if [ -f $(PREFIX)/bin/smol-pthreads ];then rm -v $(PREFIX)/bin/smol-pthreads;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 ];then rm -v $(PREFIX)/bin/smol-http;fi
if [ -f $(PREFIX)/bin/smol-http-pthreads ];then rm -v $(PREFIX)/bin/smol-http-pthreads;fi 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
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1 id="time"></h1>
<script src="index.js"></script>
</body>
</html>
+19
View File
@@ -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 "
}
+7
View File
@@ -25,3 +25,10 @@ executable(
'src/smol-http-pthreads.c', 'src/smol-http-pthreads.c',
install: true, install: true,
) )
executable(
'ws',
'src/ws.c',
dependencies: deps,
install: true,
)
+198
View File
@@ -0,0 +1,198 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <openssl/sha.h>
#include <openssl/evp.h>
#include <openssl/buffer.h>
#include <sys/sysinfo.h>
#include <signal.h>
#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;
}