diff --git a/websocket b/websocket new file mode 100755 index 0000000..37d9d23 Binary files /dev/null and b/websocket differ diff --git a/websocket.cpp b/websocket.cpp new file mode 100644 index 0000000..b3fcab3 --- /dev/null +++ b/websocket.cpp @@ -0,0 +1,179 @@ +// g++ -o websocket websocket.cpp -lssl -lcrypto +// js +// const ws = new WebSocket('ws:localhost:8080') +// ws.onmessage = e => console.log(e.data) +// ws.send('hello') + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +// Base64 кодирование (упрощенная версия) +string base64_encode(const string &in) { + const string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + string out; + int val = 0, valb = -6; + + for (unsigned char c : in) { + val = (val << 8) + c; + valb += 8; + while (valb >= 0) { + out.push_back(base64_chars[(val >> valb) & 0x3F]); + valb -= 6; + } + } + + if (valb > -6) + out.push_back(base64_chars[((val << 8) >> (valb + 8)) & 0x3F]); + + while (out.size() % 4) + out.push_back('='); + + return out; +} + +// Генерация ответа для WebSocket handshake +string get_websocket_accept(const string &client_key) { + const string magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + string combined = client_key + magic; + + unsigned char digest[SHA_DIGEST_LENGTH]; + SHA1(reinterpret_cast(combined.c_str()), combined.size(), digest); + + return base64_encode(string(reinterpret_cast(digest), SHA_DIGEST_LENGTH)); +} + +// Демаскировка данных +void unmask_data(char *data, size_t len, const char *mask) { + for(size_t i = 0; i < len; i++) { + data[i] ^= mask[i % 4]; + } +} + +int main() { + const int port = 8080; + + // Создание сокета + int server_fd = socket(AF_INET, SOCK_STREAM, 0); + if (server_fd < 0) { + cerr << "Ошибка создания сокета" << endl; + return 1; + } + + // Настройка адреса + sockaddr_in address; + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(port); + + // Бинд и листен + if (bind(server_fd, (sockaddr*)&address, sizeof(address)) < 0) { + cerr << "Ошибка бинда" << endl; + return 1; + } + + if (listen(server_fd, 1) < 0) { + cerr << "Ошибка листена" << endl; + return 1; + } + + cout << "Сервер запущен на порту " << port << endl; + + while(true) { + // Принятие соединения + sockaddr_in client_addr; + socklen_t client_len = sizeof(client_addr); + int client_socket = accept(server_fd, (sockaddr*)&client_addr, &client_len); + + if (client_socket < 0) { + cerr << "Ошибка принятия соединения" << endl; + continue; + } + + // Чтение HTTP-запроса + char buffer[4096] = {0}; + read(client_socket, buffer, 4096); + + // Поиск ключа WebSocket + string request(buffer); + size_t key_pos = request.find("Sec-WebSocket-Key: "); + if(key_pos == string::npos) { + cerr << "Неверный WebSocket запрос" << endl; + close(client_socket); + continue; + } + + key_pos += 19; + size_t key_end = request.find("\r\n", key_pos); + string client_key = request.substr(key_pos, key_end - key_pos); + + // Формирование ответа + string response = "HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: " + get_websocket_accept(client_key) + "\r\n\r\n"; + + send(client_socket, response.c_str(), response.size(), 0); + + // Цикл обработки сообщений + while(true) { + char header[2]; + if(recv(client_socket, header, 2, 0) <= 0) break; + + // Парсинг заголовка + unsigned char opcode = header[0] & 0x0F; + bool masked = (header[1] & 0x80) != 0; + size_t len = header[1] & 0x7F; + + // Чтение расширенной длины + if(len == 126) { + char ext_len[2]; + recv(client_socket, ext_len, 2, 0); + len = (ext_len[0] << 8) | ext_len[1]; + } else if(len == 127) { + cerr << "64-битная длина не поддерживается" << endl; + break; + } + + // Чтение маски + char mask[4]; + if(masked) recv(client_socket, mask, 4, 0); + + // Чтение данных + vector data(len); + recv(client_socket, data.data(), len, 0); + if(masked) unmask_data(data.data(), len, mask); + + // Обработка opcode + if(opcode == 0x8) { // Закрытие + cout << "Закрытие соединения" << endl; + break; + } + + // Эхо-ответ + unsigned char response_header[2] = {0x81, static_cast(len)}; + send(client_socket, reinterpret_cast(response_header), 2, 0); + send(client_socket, data.data(), len, 0); + } + + close(client_socket); + } + + close(server_fd); + return 0; +}