#include "include/websocket.h" websocket::websocket(std::function toLog) : toLog(std::move(toLog)) { #ifdef IBM // Required on Windows ix::initNetSystem(); #endif server = new ix::WebSocketServer(8080, "0.0.0.0"); server->setOnClientMessageCallback( [this](std::shared_ptr connectionState, ix::WebSocket &ws, const ix::WebSocketMessagePtr &msg) { this->onClientMessageCallback(connectionState, ws, msg); }); std::pair res = server->listen(); if (!res.first) { // Error handling throw std::invalid_argument("Encountered: " + res.second + "\n"); } // Run the server in the background. Server can be stopped by calling server->start(); } websocket::~websocket() { server->stop(); #ifdef IBM // Required on Windows ix::uninitNetSystem(); #endif } void websocket::onClientMessageCallback( std::shared_ptr &connectionState, ix::WebSocket &ws, const ix::WebSocketMessagePtr &msg) { if (msg->type == ix::WebSocketMessageType::Open) { std::stringstream debug_msg; debug_msg << "New connection" << std::endl; debug_msg << "Remote ip: " << connectionState->getRemoteIp() << std::endl; debug_msg << "id: " << connectionState->getId() << std::endl; debug_msg << "Uri: " << msg->openInfo.uri << std::endl; debug_msg << "Headers:" << std::endl; for (const auto &it : msg->openInfo.headers) { debug_msg << it.first << ": " << it.second << std::endl; } toLog(debug_msg.str()); const std::lock_guard guard(wsLock); webSocket = &ws; } else if (msg->type == ix::WebSocketMessageType::Close) { std::stringstream debug_msg; debug_msg << "Connection closed" << std::endl; debug_msg << "id: " << connectionState->getId() << std::endl; debug_msg << "Code: " << msg->closeInfo.code << std::endl; debug_msg << "Reason: " << msg->closeInfo.reason << std::endl; debug_msg << "Remote: " << msg->closeInfo.remote << std::endl; toLog(debug_msg.str()); const std::lock_guard guard(wsLock); webSocket = nullptr; } else if (msg->type == ix::WebSocketMessageType::Error) { std::stringstream debug_msg; debug_msg << "Connection error" << std::endl; debug_msg << "id: " << connectionState->getId() << std::endl; debug_msg << "Decompression: " << msg->errorInfo.decompressionError << std::endl; debug_msg << "HTTP status: " << msg->errorInfo.http_status << std::endl; debug_msg << "Reason: " << msg->errorInfo.reason << std::endl; debug_msg << "Retries: " << msg->errorInfo.retries << std::endl; debug_msg << "Wait time: " << msg->errorInfo.wait_time << std::endl; toLog(debug_msg.str()); const std::lock_guard guard(wsLock); webSocket = nullptr; } else if (msg->type == ix::WebSocketMessageType::Message) { if (!msg->str.empty()) { ws.send("Echo: " + msg->str, false); } } } void websocket::sendData(data d) { char *hash = (char *)calloc(2 * MD5LEN + 1, sizeof(char)); if (hash != nullptr) { if (strcmp(d.path, lastPath) != 0) { strcpy(lastPath, d.path); if (generateMD5(d.path)) { strcpy(lastHash, "NOT SET"); } } nlohmann::json json = { {"altitude", d.alt}, {"vs", d.vs}, {"ias", d.ias}, {"magHdg", d.magHeading}, {"truHdg", d.truHdg}, {"totFuel", d.totFuelKg}, {"fuelFlow", d.ff}, {"hash", lastHash}, }; { std::lock_guard lock(wsLock); if (webSocket != nullptr) { webSocket->send(json.dump(), false); } free(hash); } } } #ifdef IBM int websocket::generateMD5(const char *filepath) { BOOL bResult = FALSE; HCRYPTPROV hProv = 0; HCRYPTHASH hHash = 0; HANDLE hFile = nullptr; BYTE rgbFile[BUFSIZE] = {0}; DWORD cbRead = 0; BYTE rgbHash[MD5LEN] = {0}; DWORD cbHash = 0; // Logic to check usage goes here. hFile = CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, nullptr); // Get handle to the crypto provider if (!CryptAcquireContext(&hProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { std::stringstream debug_msg; debug_msg << "CryptAcquireContext returned with error " << GetLastError(); toLog(debug_msg.str()); CloseHandle(hFile); return 1; } if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) { std::stringstream debug_msg; debug_msg << "CryptCreateHash returned with error " << GetLastError(); toLog(debug_msg.str()); CloseHandle(hFile); CryptReleaseContext(hProv, 0); return 1; } while ((bResult = ReadFile(hFile, rgbFile, BUFSIZE, &cbRead, nullptr))) { if (0 == cbRead) { break; } if (!CryptHashData(hHash, rgbFile, cbRead, 0)) { std::stringstream debug_msg; debug_msg << "CryptHashData returned with error " << GetLastError(); toLog(debug_msg.str()); CryptReleaseContext(hProv, 0); CryptDestroyHash(hHash); CloseHandle(hFile); return 1; } } if (!bResult) { std::stringstream debug_msg; debug_msg << "ReadFile returned with error " << GetLastError(); toLog(debug_msg.str()); CryptReleaseContext(hProv, 0); CryptDestroyHash(hHash); CloseHandle(hFile); return 1; } cbHash = MD5LEN; if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0)) { to_hex((char *)rgbHash, lastHash); } else { std::stringstream debug_msg; debug_msg << "CryptGetHashParam returned with error " << GetLastError(); toLog(debug_msg.str()); } CryptDestroyHash(hHash); CryptReleaseContext(hProv, 0); CloseHandle(hFile); return 0; } #endif #ifdef APL int websocket::generateMD5(const char *filepath) { int file_descript; unsigned long file_size; char *file_buffer; unsigned char result[MD5LEN]; file_descript = open(filepath, O_RDONLY); if (file_descript < 0) return 1; file_size = get_size_by_fd(file_descript); file_buffer = (char *)mmap(0, file_size, PROT_READ, MAP_SHARED, file_descript, 0); CC_MD5_CTX context; CC_MD5_Init(&context); CC_MD5_Update(&context, file_buffer, (CC_LONG)file_size); CC_MD5_Final(result, &context); munmap(file_buffer, file_size); close(file_descript); to_hex((char *)result, lastHash); return 0; } #endif #ifdef LIN int websocket::generateMD5(const char *filepath) { int file_descriptor; unsigned long file_size; char *file_buffer; unsigned char result[MD5LEN]; file_descriptor = open(filepath, O_RDONLY); if (file_descriptor < 0) return 1; file_size = get_size_by_fd(file_descriptor); file_buffer = (char *) mmap(nullptr, file_size, PROT_READ, MAP_SHARED, file_descriptor, 0); MD5((unsigned char *)file_buffer, file_size, result); munmap(file_buffer, file_size); close(file_descriptor); to_hex((char *)result, lastHash); return 0; } #endif #if defined APL || defined LIN unsigned long get_size_by_fd(int fd) { struct stat buf { }; if (fstat(fd, &buf) < 0) exit(-1); return buf.st_size; } #endif void to_hex(const char *hash, char *buffer) { for (int i = 0; i < MD5LEN; i++) { if (buffer != nullptr) { sprintf(&buffer[2 * i], "%02x", hash[i] & 0xff); } } }