diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ecdb3b..1b83775 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(SOURCE sources/main.cpp) set(LIBS ${CMAKE_SOURCE_DIR}/libs/) set(INCLUDE ${CMAKE_SOURCE_DIR}/include/) -find_package(OpenSSL REQUIRED) +find_package(CURL REQUIRED) find_path(IXWEBSOCKET_INCLUDE_DIR 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") endif() -if(NOT OPENSSL_INCLUDE_DIR OR NOT OPENSSL_LIBRARIES) - message(FATAL_ERROR "openssl not found") +if(NOT CURL_INCLUDE_DIRS OR NOT CURL_LIBRARIES) + message(FATAL_ERROR "nghttp2 not found") endif() add_executable(${PROJECT_NAME} ${SOURCE}) @@ -23,16 +23,16 @@ add_executable(${PROJECT_NAME} ${SOURCE}) target_include_directories(${PROJECT_NAME} PRIVATE ${LIBS} ${INCLUDE} - ${OPENSSL_INCLUDE_DIR} ${IXWEBSOCKET_INCLUDE_DIR} + ${CURL_INCLUDE_DIRS} ) target_link_libraries(${PROJECT_NAME} PRIVATE - ${OPENSSL_LIBRARIES} ${IXWEBSOCKET_LIBRARIES} + ${CURL_LIBRARIES} ) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_CXX_FLAGS "-march=native -O2 -pipe") -#set(CMAKE_CXX_FLAGS "-O0 -pipe") \ No newline at end of file +#set(CMAKE_CXX_FLAGS "-O0 -pipe") diff --git a/libs/tls/Network.hpp b/libs/tls/Network.hpp index ea04103..950fecd 100644 --- a/libs/tls/Network.hpp +++ b/libs/tls/Network.hpp @@ -1,89 +1,34 @@ #ifndef TLS_NETWORK_HPP_ #define TLS_NETWORK_HPP_ -#include <openssl/ssl.h> -#include <openssl/err.h> #include <includes.h> -#include <net/if.h> -#include <netdb.h> -#include <utils/types.hpp> #include <gateway/Websocket.hpp> +#include <curl/curl.h> using std::string, std::cout, std::endl, nlohmann::json; class NetworkManager { private: + CURL* curl; + CURLcode res; 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(const NetworkManager&) = delete; NetworkManager() : web(WebSocket::getInstance()) { Logs::create(INFO, NETWORK, "Network init"); - if (!ctx) { - ctx = SSL_CTX_new(TLS_client_method()); - if (!ctx) { - Logs::create(ERROR, NETWORK, "Failed to create SSL context"); - handleSSLInitErrors(); - } - 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"); + curl_global_init(CURL_GLOBAL_DEFAULT); + curl = curl_easy_init(); + if (!curl) { + Logs::create(ERROR, NETWORK, "Failed to initialize CURL"); + abort(); } } - std::string extract(const std::string& httpResponse) { - unsigned long pos = httpResponse.find("\r\n\r\n"); - if (pos != std::string::npos) { - 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; + ~NetworkManager() { + if (curl) { + curl_easy_cleanup(curl); } - 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: static NetworkManager& getInstance() { @@ -91,44 +36,24 @@ public: static NetworkManager instance; return instance; } - ~NetworkManager() { - if (ctx) SSL_CTX_free(ctx); - close(sock); - } - std::string request(const std::string& method, const std::string& path, const std::string& data = "", bool closeConnection = true) { - if (closeConnection) createSSLConnection("discord.com", "443"); - auto net = [this, method, path, data, closeConnection, result = std::string("")]() mutable -> std::string { - std::string request = method + " " + path + " HTTP/1.1\r\n"; - request += "Host: discord.com\r\n"; - request += "Accept: application/json\r\n"; - request += "Content-Type: application/json\r\n"; - request += "Authorization: " + web.getToken() + "\r\n"; - request += "Content-Length: " + std::to_string(data.length()) + "\r\n"; - if (closeConnection) { - request += "Connection: close\r\n\r\n"; - } else { - request += "Connection: keep-alive\r\n\r\n"; - } - 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(); + std::string request(const std::string& method, const std::string& path, const std::string& data = "") { + std::string response; + if (curl) { + curl_easy_setopt(curl, CURLOPT_URL, string("https://discord.com" + path).c_str()); + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method.c_str()); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str()); + curl_slist* headers = curl_slist_append(headers, "Accept: application/json"); + headers = curl_slist_append(headers, "Content-Type: application/json"); + headers = curl_slist_append(headers, ("Authorization: " + web.getToken()).c_str()); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); + res = curl_easy_perform(curl); + if (res != 0) Logs::create(ERROR, NETWORK, "curl_easy_perform() failed: " + std::string(curl_easy_strerror(res))); + curl_slist_free_all(headers); + } + return response; } }; #endif \ No newline at end of file