http2 support

This commit is contained in:
fluttershy 2025-01-18 04:37:54 +05:00
parent e9efb4b12c
commit 9e3d5aa9e0
2 changed files with 40 additions and 115 deletions

View File

@ -6,7 +6,7 @@ set(SOURCE sources/main.cpp)
set(LIBS ${CMAKE_SOURCE_DIR}/libs/) set(LIBS ${CMAKE_SOURCE_DIR}/libs/)
set(INCLUDE ${CMAKE_SOURCE_DIR}/include/) set(INCLUDE ${CMAKE_SOURCE_DIR}/include/)
find_package(OpenSSL REQUIRED) find_package(CURL REQUIRED)
find_path(IXWEBSOCKET_INCLUDE_DIR ixwebsocket) find_path(IXWEBSOCKET_INCLUDE_DIR ixwebsocket)
find_library(IXWEBSOCKET_LIBRARIES ixwebsocket) find_library(IXWEBSOCKET_LIBRARIES ixwebsocket)
@ -14,8 +14,8 @@ if(NOT IXWEBSOCKET_INCLUDE_DIR OR NOT IXWEBSOCKET_LIBRARIES)
message(FATAL_ERROR "ixwebsocket not found") message(FATAL_ERROR "ixwebsocket not found")
endif() endif()
if(NOT OPENSSL_INCLUDE_DIR OR NOT OPENSSL_LIBRARIES) if(NOT CURL_INCLUDE_DIRS OR NOT CURL_LIBRARIES)
message(FATAL_ERROR "openssl not found") message(FATAL_ERROR "nghttp2 not found")
endif() endif()
add_executable(${PROJECT_NAME} ${SOURCE}) add_executable(${PROJECT_NAME} ${SOURCE})
@ -23,16 +23,16 @@ add_executable(${PROJECT_NAME} ${SOURCE})
target_include_directories(${PROJECT_NAME} PRIVATE target_include_directories(${PROJECT_NAME} PRIVATE
${LIBS} ${LIBS}
${INCLUDE} ${INCLUDE}
${OPENSSL_INCLUDE_DIR}
${IXWEBSOCKET_INCLUDE_DIR} ${IXWEBSOCKET_INCLUDE_DIR}
${CURL_INCLUDE_DIRS}
) )
target_link_libraries(${PROJECT_NAME} PRIVATE target_link_libraries(${PROJECT_NAME} PRIVATE
${OPENSSL_LIBRARIES}
${IXWEBSOCKET_LIBRARIES} ${IXWEBSOCKET_LIBRARIES}
${CURL_LIBRARIES}
) )
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS "-march=native -O2 -pipe") set(CMAKE_CXX_FLAGS "-march=native -O2 -pipe")
#set(CMAKE_CXX_FLAGS "-O0 -pipe") #set(CMAKE_CXX_FLAGS "-O0 -pipe")

View File

@ -1,89 +1,34 @@
#ifndef TLS_NETWORK_HPP_ #ifndef TLS_NETWORK_HPP_
#define TLS_NETWORK_HPP_ #define TLS_NETWORK_HPP_
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <includes.h> #include <includes.h>
#include <net/if.h>
#include <netdb.h>
#include <utils/types.hpp>
#include <gateway/Websocket.hpp> #include <gateway/Websocket.hpp>
#include <curl/curl.h>
using std::string, std::cout, std::endl, nlohmann::json; using std::string, std::cout, std::endl, nlohmann::json;
class NetworkManager { class NetworkManager {
private: private:
CURL* curl;
CURLcode res;
WebSocket& web; WebSocket& web;
SSL_CTX* ctx;
int sock = -1;
std::unique_ptr<SSL, decltype(&SSL_free)> ssl = { nullptr, &SSL_free };
void handleSSLInitErrors() {
ERR_print_errors_fp(stderr);
abort();
}
void createSSLConnection(const std::string& hostname, const std::string& port) {
Logs::create(INFO, NETWORK, "SSL connection");
addrinfo hints = { 0 }, *res = { 0 };
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(hostname.c_str(), port.c_str(), &hints, &res) != 0) {
Logs::create(ERROR, NETWORK, "Failed to get address info for " + hostname + ":" + port);
handleSSLInitErrors();
}
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sock == -1) {
Logs::create(ERROR, NETWORK, "Socket error");
close(sock);
handleSSLInitErrors();
}
if (connect(sock, res->ai_addr, res->ai_addrlen) == -1) {
Logs::create(ERROR, NETWORK, "Failed to connect to " + hostname + ":" + port);
close(sock);
handleSSLInitErrors();
}
ssl.reset(SSL_new(ctx));
if (!ssl) {
Logs::create(ERROR, NETWORK, "Failed to create SSL structure");
close(sock);
handleSSLInitErrors();
}
SSL_set_fd(ssl.get(), sock);
if (SSL_connect(ssl.get()) != 1) {
Logs::create(ERROR, NETWORK, "SSL connection failed");
close(sock);
handleSSLInitErrors();
}
freeaddrinfo(res);
}
NetworkManager& operator=(const NetworkManager&) = delete; NetworkManager& operator=(const NetworkManager&) = delete;
NetworkManager(const NetworkManager&) = delete; NetworkManager(const NetworkManager&) = delete;
NetworkManager() : web(WebSocket::getInstance()) { NetworkManager() : web(WebSocket::getInstance()) {
Logs::create(INFO, NETWORK, "Network init"); Logs::create(INFO, NETWORK, "Network init");
if (!ctx) { curl_global_init(CURL_GLOBAL_DEFAULT);
ctx = SSL_CTX_new(TLS_client_method()); curl = curl_easy_init();
if (!ctx) { if (!curl) {
Logs::create(ERROR, NETWORK, "Failed to create SSL context"); Logs::create(ERROR, NETWORK, "Failed to initialize CURL");
handleSSLInitErrors(); abort();
}
OPENSSL_init_ssl(0, 0);
OPENSSL_add_all_algorithms_noconf();
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION);
createSSLConnection("discord.com", "443");
} }
} }
std::string extract(const std::string& httpResponse) { ~NetworkManager() {
unsigned long pos = httpResponse.find("\r\n\r\n"); if (curl) {
if (pos != std::string::npos) { curl_easy_cleanup(curl);
std::string json, chunkSizeStr;
std::istringstream stream(httpResponse.substr(pos + 4));
while (std::getline(stream, chunkSizeStr)) {
unsigned long chunkSize = std::stoul(chunkSizeStr, nullptr, 16);
if (chunkSize == 0) break;
std::string chunk(chunkSize, '\0');
stream.read(&chunk[0], chunkSize);
json.append(chunk);
stream.ignore(2);
}
return json;
} }
return ""; curl_global_cleanup();
}
static unsigned long WriteCallback(void* contents, unsigned long size, unsigned long nmemb, void* userp) {
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
} }
public: public:
static NetworkManager& getInstance() { static NetworkManager& getInstance() {
@ -91,44 +36,24 @@ public:
static NetworkManager instance; static NetworkManager instance;
return instance; return instance;
} }
~NetworkManager() { std::string request(const std::string& method, const std::string& path, const std::string& data = "") {
if (ctx) SSL_CTX_free(ctx); std::string response;
close(sock); if (curl) {
} curl_easy_setopt(curl, CURLOPT_URL, string("https://discord.com" + path).c_str());
std::string request(const std::string& method, const std::string& path, const std::string& data = "", bool closeConnection = true) { curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method.c_str());
if (closeConnection) createSSLConnection("discord.com", "443"); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
auto net = [this, method, path, data, closeConnection, result = std::string("")]() mutable -> std::string { curl_slist* headers = curl_slist_append(headers, "Accept: application/json");
std::string request = method + " " + path + " HTTP/1.1\r\n"; headers = curl_slist_append(headers, "Content-Type: application/json");
request += "Host: discord.com\r\n"; headers = curl_slist_append(headers, ("Authorization: " + web.getToken()).c_str());
request += "Accept: application/json\r\n"; curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
request += "Content-Type: application/json\r\n"; curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
request += "Authorization: " + web.getToken() + "\r\n"; curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
request += "Content-Length: " + std::to_string(data.length()) + "\r\n"; curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
if (closeConnection) { res = curl_easy_perform(curl);
request += "Connection: close\r\n\r\n"; if (res != 0) Logs::create(ERROR, NETWORK, "curl_easy_perform() failed: " + std::string(curl_easy_strerror(res)));
} else { curl_slist_free_all(headers);
request += "Connection: keep-alive\r\n\r\n"; }
} return response;
request += data;
if (SSL_write(ssl.get(), request.c_str(), request.length()) <= 0) {
Logs::create(ERROR, NETWORK, "Failed to send request");
handleSSLInitErrors();
return "";
}
Logs::create(INFO, NETWORK, "Request " + method + " " + path);
if (closeConnection) {
std::vector<char> buffer(1024);
int bytesRead;
while ((bytesRead = SSL_read(ssl.get(), buffer.data(), buffer.size())) > 0) {
result.append(buffer.data(), bytesRead);
if (bytesRead == buffer.size()) {
buffer.resize(buffer.size() * 2);
}
}
}
return extract(result);
};
return net();
} }
}; };
#endif #endif