Files
openrouter/websocket.cpp
T
wt c793bb2743
Prepare Build and Testing executable binary / Prepare-Build-Testing-With-Make (push) Has been cancelled
Prepare Build and Testing executable binary / Prepare-Build-Testing-With-CMake (push) Has been cancelled
Prepare Build and Testing executable binary / Prepare-Build-Testing-With-Meson (push) Has been cancelled
added websocket example
2025-04-08 18:49:51 +07:00

180 lines
5.4 KiB
C++

// 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 <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sstream>
#include <iomanip>
#include <openssl/sha.h>
#include <openssl/evp.h>
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<const unsigned char*>(combined.c_str()), combined.size(), digest);
return base64_encode(string(reinterpret_cast<char*>(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<char> 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<char>(len)};
send(client_socket, reinterpret_cast<char*>(response_header), 2, 0);
send(client_socket, data.data(), len, 0);
}
close(client_socket);
}
close(server_fd);
return 0;
}