From 76fd8a65f51238634ee9bcd491f4f6766da22c36 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 20 Jan 2017 14:36:13 +0100 Subject: [PATCH] [LineEndings] Add lineendings patch again --- _.gitattributes => .gitattributes | 1 + src/Components/Modules/Download.cpp | 1212 +++++++++++++-------------- src/Proto/auth.proto | 36 +- 3 files changed, 625 insertions(+), 624 deletions(-) rename _.gitattributes => .gitattributes (72%) diff --git a/_.gitattributes b/.gitattributes similarity index 72% rename from _.gitattributes rename to .gitattributes index a4254333..38435109 100644 --- a/_.gitattributes +++ b/.gitattributes @@ -1,3 +1,4 @@ *.hpp eol=crlf *.cpp eol=crlf *.lua eol=crlf +*.proto eol=crlf diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index be62758f..7fa13e07 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -1,606 +1,606 @@ -#include "STDInclude.hpp" - -namespace Components -{ - mg_mgr Download::Mgr; - Download::ClientDownload Download::CLDownload; - -#pragma region Client - - void Download::InitiateClientDownload(std::string mod) - { - if (Download::CLDownload.running) return; - - Localization::SetTemp("MPUI_EST_TIME_LEFT", Utils::String::FormatTimeSpan(0)); - Localization::SetTemp("MPUI_PROGRESS_DL", "(0/0) %"); - Localization::SetTemp("MPUI_TRANS_RATE", "0.0 MB/s"); - - Command::Execute("openmenu mod_download_popmenu", false); - - Download::CLDownload.running = true; - Download::CLDownload.mod = mod; - Download::CLDownload.terminateThread = false; - Download::CLDownload.totalBytes = 0; - Download::CLDownload.lastTimeStamp = 0; - Download::CLDownload.downBytes = 0; - Download::CLDownload.timeStampBytes = 0; - Download::CLDownload.target = Party::Target(); - Download::CLDownload.thread = std::thread(Download::ModDownloader, &Download::CLDownload); - } - - bool Download::ParseModList(ClientDownload* download, std::string list) - { - if (!download) return false; - download->files.clear(); - - std::string error; - json11::Json listData = json11::Json::parse(list, error); - - - if (!error.empty() || !listData.is_array()) return false; - - download->totalBytes = 0; - - for (auto& file : listData.array_items()) - { - if (!file.is_object()) return false; - - auto hash = file["hash"]; - auto name = file["name"]; - auto size = file["size"]; - - if (!hash.is_string() || !name.is_string() || !size.is_number()) return false; - - Download::ClientDownload::File fileEntry; - fileEntry.name = name.string_value(); - fileEntry.hash = hash.string_value(); - fileEntry.size = static_cast(size.number_value()); - - if (!fileEntry.name.empty()) - { - download->files.push_back(fileEntry); - download->totalBytes += fileEntry.size; - } - } - - return true; - } - - void Download::DownloadHandler(mg_connection *nc, int ev, void* ev_data) - { - http_message* hm = reinterpret_cast(ev_data); - Download::FileDownload* fDownload = reinterpret_cast(nc->mgr->user_data); - - if (ev == MG_EV_CONNECT) - { - if (hm->message.p) - { - fDownload->downloading = false; - return; - } - } - - if (ev == MG_EV_RECV) - { - size_t bytes = static_cast(*reinterpret_cast(ev_data)); - fDownload->receivedBytes += bytes; - fDownload->download->downBytes += bytes; - fDownload->download->timeStampBytes += bytes; - - double progress = 0; - if (fDownload->download->totalBytes) - { - progress = (100.0 / fDownload->download->totalBytes) * fDownload->download->downBytes; - } - - Localization::SetTemp("MPUI_PROGRESS_DL", Utils::String::VA("(%d/%d) %d%%", fDownload->index + 1, fDownload->download->files.size(), static_cast(progress))); - - int delta = Game::Sys_Milliseconds() - fDownload->download->lastTimeStamp; - if (delta > 300) - { - bool doFormat = fDownload->download->lastTimeStamp != 0; - fDownload->download->lastTimeStamp = Game::Sys_Milliseconds(); - - size_t dataLeft = fDownload->download->totalBytes - fDownload->download->downBytes; - - int timeLeft = 0; - if (fDownload->download->timeStampBytes) - { - double timeLeftD = ((1.0 * dataLeft) / fDownload->download->timeStampBytes) * delta; - timeLeft = static_cast(timeLeftD); - } - - if (doFormat) - { - Localization::SetTemp("MPUI_EST_TIME_LEFT", Utils::String::FormatTimeSpan(timeLeft)); - Localization::SetTemp("MPUI_TRANS_RATE", Utils::String::FormatBandwidth(fDownload->download->timeStampBytes, delta)); - } - - fDownload->download->timeStampBytes = 0; - } - } - - if (ev == MG_EV_HTTP_REPLY) - { - nc->flags |= MG_F_CLOSE_IMMEDIATELY; - fDownload->buffer = std::string(hm->body.p, hm->body.len); - fDownload->downloading = false; - return; - } - } - - bool Download::DownloadFile(ClientDownload* download, unsigned int index) - { - if (!download || download->files.size() <= index) return false; - - auto file = download->files[index]; - - std::string path = download->mod + "/" + file.name; - if (Utils::IO::FileExists(path)) - { - std::string data = Utils::IO::ReadFile(path); - - if (data.size() == file.size && Utils::String::DumpHex(Utils::Cryptography::SHA256::Compute(data), "") == file.hash) - { - download->totalBytes += file.size; - return true; - } - } - - std::string url = "http://" + download->target.getString() + "/file/" + file.name; - - Download::FileDownload fDownload; - fDownload.file = file; - fDownload.index = index; - fDownload.download = download; - fDownload.downloading = true; - fDownload.receivedBytes = 0; - - Utils::String::Replace(url, " ", "%20"); - - download->valid = true; - mg_mgr_init(&download->mgr, &fDownload); - mg_connect_http(&download->mgr, Download::DownloadHandler, url.data(), NULL, NULL); - - while (fDownload.downloading && !fDownload.download->terminateThread) - { - mg_mgr_poll(&download->mgr, 0); - } - - mg_mgr_free(&download->mgr); - download->valid = false; - - if (fDownload.buffer.size() != file.size || Utils::String::DumpHex(Utils::Cryptography::SHA256::Compute(fDownload.buffer), "") != file.hash) - { - return false; - } - - Utils::IO::CreateDirectory(download->mod); - Utils::IO::WriteFile(path, fDownload.buffer); - - return true; - } - - void Download::ModDownloader(ClientDownload* download) - { - if (!download) download = &Download::CLDownload; - - std::string host = "http://" + download->target.getString(); - std::string list = Utils::WebIO("IW4x", host + "/list").setTimeout(5000)->get(); - - if (list.empty()) - { - if (download->terminateThread) return; - - download->thread.detach(); - download->clear(); - - QuickPatch::Once([] () - { - Party::ConnectError("Failed to download the modlist!"); - }); - - return; - } - - if (download->terminateThread) return; - - if (!Download::ParseModList(download, list)) - { - if (download->terminateThread) return; - - download->thread.detach(); - download->clear(); - - QuickPatch::Once([] () - { - Party::ConnectError("Failed to parse the modlist!"); - }); - - return; - } - - if (download->terminateThread) return; - - std::string mod = download->mod; - - for (unsigned int i = 0; i < download->files.size(); ++i) - { - if (download->terminateThread) return; - - if (!Download::DownloadFile(download, i)) - { - if (download->terminateThread) return; - - mod = Utils::String::VA("Failed to download file: %s!", download->files[i].name.data()); - download->thread.detach(); - download->clear(); - - QuickPatch::Once([mod] () - { - Dvar::Var("partyend_reason").set(mod); - - Localization::ClearTemp(); - Command::Execute("closemenu mod_download_popmenu"); - Command::Execute("openmenu menu_xboxlive_partyended"); - }); - - return; - } - } - - if (download->terminateThread) return; - - download->thread.detach(); - download->clear(); - - // Run this on the main thread - QuickPatch::Once([mod] () - { - auto fsGame = Dvar::Var("fs_game"); - fsGame.set(mod); - fsGame.get()->modified = true; - - Localization::ClearTemp(); - Command::Execute("closemenu mod_download_popmenu", false); - - if (Dvar::Var("cl_modVidRestart").get()) - { - Command::Execute("vid_restart", false); - } - - Command::Execute("reconnect", false); - }); - } - -#pragma endregion - -#pragma region Server - - bool Download::IsClient(mg_connection *nc) - { - return (Download::GetClient(nc) != nullptr); - } - - Game::client_t* Download::GetClient(mg_connection *nc) - { - Network::Address address(nc->sa.sa); - - for (int i = 0; i < *Game::svs_numclients; ++i) - { - Game::client_t* client = &Game::svs_clients[i]; - - if (client->state >= 3) - { - if (address.getIP().full == Network::Address(client->addr).getIP().full) - { - return client; - } - } - } - - return nullptr; - } - - void Download::Forbid(mg_connection *nc) - { - mg_printf(nc, "HTTP/1.1 403 Forbidden\r\n" - "Content-Type: text/html\r\n" - "Connection: close\r\n" - "\r\n" - "403 - Forbidden"); - - nc->flags |= MG_F_SEND_AND_CLOSE; - } - - void Download::ListHandler(mg_connection* nc, int ev, void* /*ev_data*/) - { - // Only handle http requests - if (ev != MG_EV_HTTP_REQUEST) return; - -// if (!Download::IsClient(nc)) -// { -// Download::Forbid(nc); -// } -// else - { - static std::string fsGamePre; - static json11::Json jsonList; - - std::string fsGame = Dvar::Var("fs_game").get(); - - if (!fsGame.empty() && fsGame != fsGamePre) - { - std::vector fileList; - - fsGamePre = fsGame; - - std::string path = Dvar::Var("fs_basepath").get() + "\\" + fsGame; - auto list = FileSystem::GetSysFileList(path, "iwd", false); - - list.push_back("mod.ff"); - - for (auto i = list.begin(); i != list.end(); ++i) - { - std::string filename = path + "\\" + *i; - if (strstr(i->data(), "_svr_") == NULL && Utils::IO::FileExists(filename)) - { - std::map file; - std::string fileBuffer = Utils::IO::ReadFile(path + "\\" + *i); - - file["name"] = *i; - file["size"] = static_cast(fileBuffer.size()); - file["hash"] = Utils::Cryptography::SHA256::Compute(fileBuffer, true); - - fileList.push_back(file); - } - } - - jsonList = fileList; - } - - mg_printf(nc, - "HTTP/1.1 200 OK\r\n" - "Content-Type: application/json\r\n" - "Connection: close\r\n" - "\r\n" - "%s", jsonList.dump().data()); - - nc->flags |= MG_F_SEND_AND_CLOSE; - } - } - - void Download::FileHandler(mg_connection *nc, int ev, void *ev_data) - { - // Only handle http requests - if (ev != MG_EV_HTTP_REQUEST) return; - - http_message* message = reinterpret_cast(ev_data); - -// if (!Download::IsClient(nc)) -// { -// Download::Forbid(nc); -// } -// else - { - std::string url(message->uri.p, message->uri.len); - Utils::String::Replace(url, "\\", "/"); - url = url.substr(6); - - Utils::String::Replace(url, "%20", " "); - - if (url.find_first_of("/") != std::string::npos || (!Utils::String::EndsWith(url, ".iwd") && url != "mod.ff") || strstr(url.data(), "_svr_") != NULL) - { - Download::Forbid(nc); - return; - } - - std::string fsGame = Dvar::Var("fs_game").get(); - std::string path = Dvar::Var("fs_basepath").get() + "\\" + fsGame + "\\" + url; - - if (fsGame.empty() || !Utils::IO::FileExists(path)) - { - mg_printf(nc, - "HTTP/1.1 404 Not Found\r\n" - "Content-Type: text/html\r\n" - "Connection: close\r\n" - "\r\n" - "404 - Not Found %s", path.data()); - } - else - { - std::string file = Utils::IO::ReadFile(path); - - mg_printf(nc, - "HTTP/1.1 200 OK\r\n" - "Content-Type: application/octet-stream\r\n" - "Content-Length: %d\r\n" - "Connection: close\r\n" - "\r\n", file.size()); - - mg_send(nc, file.data(), static_cast(file.size())); - } - - nc->flags |= MG_F_SEND_AND_CLOSE; - } - } - - void Download::InfoHandler(mg_connection* nc, int ev, void* /*ev_data*/) - { - // Only handle http requests - if (ev != MG_EV_HTTP_REQUEST) return; - - //http_message* message = reinterpret_cast(ev_data); - - Utils::InfoString status = ServerInfo::GetInfo(); - - std::map info; - info["status"] = status.to_json(); - - std::vector players; - - // Build player list - for (int i = 0; i < atoi(status.get("sv_maxclients").data()); ++i) // Maybe choose 18 here? - { - std::map playerInfo; - playerInfo["score"] = 0; - playerInfo["ping"] = 0; - playerInfo["name"] = ""; - - if (Dvar::Var("sv_running").get()) - { - if (Game::svs_clients[i].state < 3) continue; - - playerInfo["score"] = Game::SV_GameClientNum_Score(i); - playerInfo["ping"] = Game::svs_clients[i].ping; - playerInfo["name"] = Game::svs_clients[i].name; - } - else - { - // Score and ping are irrelevant - const char* namePtr = Game::PartyHost_GetMemberName(reinterpret_cast(0x1081C00), i); - if (!namePtr || !namePtr[0]) continue; - - playerInfo["name"] = namePtr; - } - - players.push_back(playerInfo); - } - - info["players"] = players; - - mg_printf(nc, - "HTTP/1.1 200 OK\r\n" - "Content-Type: application/json\r\n" - "Connection: close\r\n" - "Access-Control-Allow-Origin: *\r\n" - "\r\n" - "%s", json11::Json(info).dump().data()); - - nc->flags |= MG_F_SEND_AND_CLOSE; - } - - void Download::EventHandler(mg_connection *nc, int ev, void *ev_data) - { - // Only handle http requests - if (ev != MG_EV_HTTP_REQUEST) return; - - http_message* message = reinterpret_cast(ev_data); - -// if (message->uri.p, message->uri.len == "/"s) -// { -// mg_printf(nc, -// "HTTP/1.1 200 OK\r\n" -// "Content-Type: text/html\r\n" -// "Connection: close\r\n" -// "\r\n" -// "Hi fella!
You are%s connected to this server!", (Download::IsClient(nc) ? " " : " not")); -// -// Game::client_t* client = Download::GetClient(nc); -// -// if (client) -// { -// mg_printf(nc, "
Hello %s!", client->name); -// } -// } -// else - { - //std::string path = (Dvar::Var("fs_basepath").get() + "\\" BASEGAME "\\html"); - //mg_serve_http_opts opts = { 0 }; - //opts.document_root = path.data(); - //mg_serve_http(nc, message, opts); - - FileSystem::File file; - std::string url = "html" + std::string(message->uri.p, message->uri.len); - - if (Utils::String::EndsWith(url, "/")) - { - url.append("index.html"); - file = FileSystem::File(url); - } - else - { - file = FileSystem::File(url); - - if (!file.exists()) - { - url.append("/index.html"); - file = FileSystem::File(url); - } - } - - std::string mimeType = Utils::GetMimeType(url); - - if (file.exists()) - { - std::string buffer = file.getBuffer(); - - mg_printf(nc, - "HTTP/1.1 200 OK\r\n" - "Content-Type: %s\r\n" - "Content-Length: %d\r\n" - "Connection: close\r\n" - "\r\n", mimeType.data(), buffer.size()); - - mg_send(nc, buffer.data(), static_cast(buffer.size())); - } - else - { - mg_printf(nc, - "HTTP/1.1 404 Not Found\r\n" - "Content-Type: text/html\r\n" - "Connection: close\r\n" - "\r\n" - "404 - Not Found"); - } - } - - nc->flags |= MG_F_SEND_AND_CLOSE; - } - -#pragma endregion - - Download::Download() - { - if (Dedicated::IsEnabled()) - { - mg_mgr_init(&Download::Mgr, NULL); - - Network::OnStart([] () - { - mg_connection* nc = mg_bind(&Download::Mgr, Utils::String::VA("%hu", (Dvar::Var("net_port").get() & 0xFFFF)), Download::EventHandler); - - // Handle special requests - mg_register_http_endpoint(nc, "/info", Download::InfoHandler); - mg_register_http_endpoint(nc, "/list", Download::ListHandler); - mg_register_http_endpoint(nc, "/file", Download::FileHandler); - - mg_set_protocol_http_websocket(nc); - }); - - QuickPatch::OnFrame([] - { - mg_mgr_poll(&Download::Mgr, 0); - }); - } - else - { - UIScript::Add("mod_download_cancel", [] (UIScript::Token) - { - Download::CLDownload.clear(); - }); - } - } - - Download::~Download() - { - if (Dedicated::IsEnabled()) - { - mg_mgr_free(&Download::Mgr); - } - else - { - Download::CLDownload.clear(); - } - } -} +#include "STDInclude.hpp" + +namespace Components +{ + mg_mgr Download::Mgr; + Download::ClientDownload Download::CLDownload; + +#pragma region Client + + void Download::InitiateClientDownload(std::string mod) + { + if (Download::CLDownload.running) return; + + Localization::SetTemp("MPUI_EST_TIME_LEFT", Utils::String::FormatTimeSpan(0)); + Localization::SetTemp("MPUI_PROGRESS_DL", "(0/0) %"); + Localization::SetTemp("MPUI_TRANS_RATE", "0.0 MB/s"); + + Command::Execute("openmenu mod_download_popmenu", false); + + Download::CLDownload.running = true; + Download::CLDownload.mod = mod; + Download::CLDownload.terminateThread = false; + Download::CLDownload.totalBytes = 0; + Download::CLDownload.lastTimeStamp = 0; + Download::CLDownload.downBytes = 0; + Download::CLDownload.timeStampBytes = 0; + Download::CLDownload.target = Party::Target(); + Download::CLDownload.thread = std::thread(Download::ModDownloader, &Download::CLDownload); + } + + bool Download::ParseModList(ClientDownload* download, std::string list) + { + if (!download) return false; + download->files.clear(); + + std::string error; + json11::Json listData = json11::Json::parse(list, error); + + + if (!error.empty() || !listData.is_array()) return false; + + download->totalBytes = 0; + + for (auto& file : listData.array_items()) + { + if (!file.is_object()) return false; + + auto hash = file["hash"]; + auto name = file["name"]; + auto size = file["size"]; + + if (!hash.is_string() || !name.is_string() || !size.is_number()) return false; + + Download::ClientDownload::File fileEntry; + fileEntry.name = name.string_value(); + fileEntry.hash = hash.string_value(); + fileEntry.size = static_cast(size.number_value()); + + if (!fileEntry.name.empty()) + { + download->files.push_back(fileEntry); + download->totalBytes += fileEntry.size; + } + } + + return true; + } + + void Download::DownloadHandler(mg_connection *nc, int ev, void* ev_data) + { + http_message* hm = reinterpret_cast(ev_data); + Download::FileDownload* fDownload = reinterpret_cast(nc->mgr->user_data); + + if (ev == MG_EV_CONNECT) + { + if (hm->message.p) + { + fDownload->downloading = false; + return; + } + } + + if (ev == MG_EV_RECV) + { + size_t bytes = static_cast(*reinterpret_cast(ev_data)); + fDownload->receivedBytes += bytes; + fDownload->download->downBytes += bytes; + fDownload->download->timeStampBytes += bytes; + + double progress = 0; + if (fDownload->download->totalBytes) + { + progress = (100.0 / fDownload->download->totalBytes) * fDownload->download->downBytes; + } + + Localization::SetTemp("MPUI_PROGRESS_DL", Utils::String::VA("(%d/%d) %d%%", fDownload->index + 1, fDownload->download->files.size(), static_cast(progress))); + + int delta = Game::Sys_Milliseconds() - fDownload->download->lastTimeStamp; + if (delta > 300) + { + bool doFormat = fDownload->download->lastTimeStamp != 0; + fDownload->download->lastTimeStamp = Game::Sys_Milliseconds(); + + size_t dataLeft = fDownload->download->totalBytes - fDownload->download->downBytes; + + int timeLeft = 0; + if (fDownload->download->timeStampBytes) + { + double timeLeftD = ((1.0 * dataLeft) / fDownload->download->timeStampBytes) * delta; + timeLeft = static_cast(timeLeftD); + } + + if (doFormat) + { + Localization::SetTemp("MPUI_EST_TIME_LEFT", Utils::String::FormatTimeSpan(timeLeft)); + Localization::SetTemp("MPUI_TRANS_RATE", Utils::String::FormatBandwidth(fDownload->download->timeStampBytes, delta)); + } + + fDownload->download->timeStampBytes = 0; + } + } + + if (ev == MG_EV_HTTP_REPLY) + { + nc->flags |= MG_F_CLOSE_IMMEDIATELY; + fDownload->buffer = std::string(hm->body.p, hm->body.len); + fDownload->downloading = false; + return; + } + } + + bool Download::DownloadFile(ClientDownload* download, unsigned int index) + { + if (!download || download->files.size() <= index) return false; + + auto file = download->files[index]; + + std::string path = download->mod + "/" + file.name; + if (Utils::IO::FileExists(path)) + { + std::string data = Utils::IO::ReadFile(path); + + if (data.size() == file.size && Utils::String::DumpHex(Utils::Cryptography::SHA256::Compute(data), "") == file.hash) + { + download->totalBytes += file.size; + return true; + } + } + + std::string url = "http://" + download->target.getString() + "/file/" + file.name; + + Download::FileDownload fDownload; + fDownload.file = file; + fDownload.index = index; + fDownload.download = download; + fDownload.downloading = true; + fDownload.receivedBytes = 0; + + Utils::String::Replace(url, " ", "%20"); + + download->valid = true; + mg_mgr_init(&download->mgr, &fDownload); + mg_connect_http(&download->mgr, Download::DownloadHandler, url.data(), NULL, NULL); + + while (fDownload.downloading && !fDownload.download->terminateThread) + { + mg_mgr_poll(&download->mgr, 0); + } + + mg_mgr_free(&download->mgr); + download->valid = false; + + if (fDownload.buffer.size() != file.size || Utils::String::DumpHex(Utils::Cryptography::SHA256::Compute(fDownload.buffer), "") != file.hash) + { + return false; + } + + Utils::IO::CreateDirectory(download->mod); + Utils::IO::WriteFile(path, fDownload.buffer); + + return true; + } + + void Download::ModDownloader(ClientDownload* download) + { + if (!download) download = &Download::CLDownload; + + std::string host = "http://" + download->target.getString(); + std::string list = Utils::WebIO("IW4x", host + "/list").setTimeout(5000)->get(); + + if (list.empty()) + { + if (download->terminateThread) return; + + download->thread.detach(); + download->clear(); + + QuickPatch::Once([] () + { + Party::ConnectError("Failed to download the modlist!"); + }); + + return; + } + + if (download->terminateThread) return; + + if (!Download::ParseModList(download, list)) + { + if (download->terminateThread) return; + + download->thread.detach(); + download->clear(); + + QuickPatch::Once([] () + { + Party::ConnectError("Failed to parse the modlist!"); + }); + + return; + } + + if (download->terminateThread) return; + + std::string mod = download->mod; + + for (unsigned int i = 0; i < download->files.size(); ++i) + { + if (download->terminateThread) return; + + if (!Download::DownloadFile(download, i)) + { + if (download->terminateThread) return; + + mod = Utils::String::VA("Failed to download file: %s!", download->files[i].name.data()); + download->thread.detach(); + download->clear(); + + QuickPatch::Once([mod] () + { + Dvar::Var("partyend_reason").set(mod); + + Localization::ClearTemp(); + Command::Execute("closemenu mod_download_popmenu"); + Command::Execute("openmenu menu_xboxlive_partyended"); + }); + + return; + } + } + + if (download->terminateThread) return; + + download->thread.detach(); + download->clear(); + + // Run this on the main thread + QuickPatch::Once([mod] () + { + auto fsGame = Dvar::Var("fs_game"); + fsGame.set(mod); + fsGame.get()->modified = true; + + Localization::ClearTemp(); + Command::Execute("closemenu mod_download_popmenu", false); + + if (Dvar::Var("cl_modVidRestart").get()) + { + Command::Execute("vid_restart", false); + } + + Command::Execute("reconnect", false); + }); + } + +#pragma endregion + +#pragma region Server + + bool Download::IsClient(mg_connection *nc) + { + return (Download::GetClient(nc) != nullptr); + } + + Game::client_t* Download::GetClient(mg_connection *nc) + { + Network::Address address(nc->sa.sa); + + for (int i = 0; i < *Game::svs_numclients; ++i) + { + Game::client_t* client = &Game::svs_clients[i]; + + if (client->state >= 3) + { + if (address.getIP().full == Network::Address(client->addr).getIP().full) + { + return client; + } + } + } + + return nullptr; + } + + void Download::Forbid(mg_connection *nc) + { + mg_printf(nc, "HTTP/1.1 403 Forbidden\r\n" + "Content-Type: text/html\r\n" + "Connection: close\r\n" + "\r\n" + "403 - Forbidden"); + + nc->flags |= MG_F_SEND_AND_CLOSE; + } + + void Download::ListHandler(mg_connection* nc, int ev, void* /*ev_data*/) + { + // Only handle http requests + if (ev != MG_EV_HTTP_REQUEST) return; + +// if (!Download::IsClient(nc)) +// { +// Download::Forbid(nc); +// } +// else + { + static std::string fsGamePre; + static json11::Json jsonList; + + std::string fsGame = Dvar::Var("fs_game").get(); + + if (!fsGame.empty() && fsGame != fsGamePre) + { + std::vector fileList; + + fsGamePre = fsGame; + + std::string path = Dvar::Var("fs_basepath").get() + "\\" + fsGame; + auto list = FileSystem::GetSysFileList(path, "iwd", false); + + list.push_back("mod.ff"); + + for (auto i = list.begin(); i != list.end(); ++i) + { + std::string filename = path + "\\" + *i; + if (strstr(i->data(), "_svr_") == NULL && Utils::IO::FileExists(filename)) + { + std::map file; + std::string fileBuffer = Utils::IO::ReadFile(path + "\\" + *i); + + file["name"] = *i; + file["size"] = static_cast(fileBuffer.size()); + file["hash"] = Utils::Cryptography::SHA256::Compute(fileBuffer, true); + + fileList.push_back(file); + } + } + + jsonList = fileList; + } + + mg_printf(nc, + "HTTP/1.1 200 OK\r\n" + "Content-Type: application/json\r\n" + "Connection: close\r\n" + "\r\n" + "%s", jsonList.dump().data()); + + nc->flags |= MG_F_SEND_AND_CLOSE; + } + } + + void Download::FileHandler(mg_connection *nc, int ev, void *ev_data) + { + // Only handle http requests + if (ev != MG_EV_HTTP_REQUEST) return; + + http_message* message = reinterpret_cast(ev_data); + +// if (!Download::IsClient(nc)) +// { +// Download::Forbid(nc); +// } +// else + { + std::string url(message->uri.p, message->uri.len); + Utils::String::Replace(url, "\\", "/"); + url = url.substr(6); + + Utils::String::Replace(url, "%20", " "); + + if (url.find_first_of("/") != std::string::npos || (!Utils::String::EndsWith(url, ".iwd") && url != "mod.ff") || strstr(url.data(), "_svr_") != NULL) + { + Download::Forbid(nc); + return; + } + + std::string fsGame = Dvar::Var("fs_game").get(); + std::string path = Dvar::Var("fs_basepath").get() + "\\" + fsGame + "\\" + url; + + if (fsGame.empty() || !Utils::IO::FileExists(path)) + { + mg_printf(nc, + "HTTP/1.1 404 Not Found\r\n" + "Content-Type: text/html\r\n" + "Connection: close\r\n" + "\r\n" + "404 - Not Found %s", path.data()); + } + else + { + std::string file = Utils::IO::ReadFile(path); + + mg_printf(nc, + "HTTP/1.1 200 OK\r\n" + "Content-Type: application/octet-stream\r\n" + "Content-Length: %d\r\n" + "Connection: close\r\n" + "\r\n", file.size()); + + mg_send(nc, file.data(), static_cast(file.size())); + } + + nc->flags |= MG_F_SEND_AND_CLOSE; + } + } + + void Download::InfoHandler(mg_connection* nc, int ev, void* /*ev_data*/) + { + // Only handle http requests + if (ev != MG_EV_HTTP_REQUEST) return; + + //http_message* message = reinterpret_cast(ev_data); + + Utils::InfoString status = ServerInfo::GetInfo(); + + std::map info; + info["status"] = status.to_json(); + + std::vector players; + + // Build player list + for (int i = 0; i < atoi(status.get("sv_maxclients").data()); ++i) // Maybe choose 18 here? + { + std::map playerInfo; + playerInfo["score"] = 0; + playerInfo["ping"] = 0; + playerInfo["name"] = ""; + + if (Dvar::Var("sv_running").get()) + { + if (Game::svs_clients[i].state < 3) continue; + + playerInfo["score"] = Game::SV_GameClientNum_Score(i); + playerInfo["ping"] = Game::svs_clients[i].ping; + playerInfo["name"] = Game::svs_clients[i].name; + } + else + { + // Score and ping are irrelevant + const char* namePtr = Game::PartyHost_GetMemberName(reinterpret_cast(0x1081C00), i); + if (!namePtr || !namePtr[0]) continue; + + playerInfo["name"] = namePtr; + } + + players.push_back(playerInfo); + } + + info["players"] = players; + + mg_printf(nc, + "HTTP/1.1 200 OK\r\n" + "Content-Type: application/json\r\n" + "Connection: close\r\n" + "Access-Control-Allow-Origin: *\r\n" + "\r\n" + "%s", json11::Json(info).dump().data()); + + nc->flags |= MG_F_SEND_AND_CLOSE; + } + + void Download::EventHandler(mg_connection *nc, int ev, void *ev_data) + { + // Only handle http requests + if (ev != MG_EV_HTTP_REQUEST) return; + + http_message* message = reinterpret_cast(ev_data); + +// if (message->uri.p, message->uri.len == "/"s) +// { +// mg_printf(nc, +// "HTTP/1.1 200 OK\r\n" +// "Content-Type: text/html\r\n" +// "Connection: close\r\n" +// "\r\n" +// "Hi fella!
You are%s connected to this server!", (Download::IsClient(nc) ? " " : " not")); +// +// Game::client_t* client = Download::GetClient(nc); +// +// if (client) +// { +// mg_printf(nc, "
Hello %s!", client->name); +// } +// } +// else + { + //std::string path = (Dvar::Var("fs_basepath").get() + "\\" BASEGAME "\\html"); + //mg_serve_http_opts opts = { 0 }; + //opts.document_root = path.data(); + //mg_serve_http(nc, message, opts); + + FileSystem::File file; + std::string url = "html" + std::string(message->uri.p, message->uri.len); + + if (Utils::String::EndsWith(url, "/")) + { + url.append("index.html"); + file = FileSystem::File(url); + } + else + { + file = FileSystem::File(url); + + if (!file.exists()) + { + url.append("/index.html"); + file = FileSystem::File(url); + } + } + + std::string mimeType = Utils::GetMimeType(url); + + if (file.exists()) + { + std::string buffer = file.getBuffer(); + + mg_printf(nc, + "HTTP/1.1 200 OK\r\n" + "Content-Type: %s\r\n" + "Content-Length: %d\r\n" + "Connection: close\r\n" + "\r\n", mimeType.data(), buffer.size()); + + mg_send(nc, buffer.data(), static_cast(buffer.size())); + } + else + { + mg_printf(nc, + "HTTP/1.1 404 Not Found\r\n" + "Content-Type: text/html\r\n" + "Connection: close\r\n" + "\r\n" + "404 - Not Found"); + } + } + + nc->flags |= MG_F_SEND_AND_CLOSE; + } + +#pragma endregion + + Download::Download() + { + if (Dedicated::IsEnabled()) + { + mg_mgr_init(&Download::Mgr, NULL); + + Network::OnStart([] () + { + mg_connection* nc = mg_bind(&Download::Mgr, Utils::String::VA("%hu", (Dvar::Var("net_port").get() & 0xFFFF)), Download::EventHandler); + + // Handle special requests + mg_register_http_endpoint(nc, "/info", Download::InfoHandler); + mg_register_http_endpoint(nc, "/list", Download::ListHandler); + mg_register_http_endpoint(nc, "/file", Download::FileHandler); + + mg_set_protocol_http_websocket(nc); + }); + + QuickPatch::OnFrame([] + { + mg_mgr_poll(&Download::Mgr, 0); + }); + } + else + { + UIScript::Add("mod_download_cancel", [] (UIScript::Token) + { + Download::CLDownload.clear(); + }); + } + } + + Download::~Download() + { + if (Dedicated::IsEnabled()) + { + mg_mgr_free(&Download::Mgr); + } + else + { + Download::CLDownload.clear(); + } + } +} diff --git a/src/Proto/auth.proto b/src/Proto/auth.proto index cff320a0..ed7ecdba 100644 --- a/src/Proto/auth.proto +++ b/src/Proto/auth.proto @@ -1,18 +1,18 @@ -syntax = "proto3"; - -package Proto.Auth; - -message Certificate -{ - bytes privatekey = 1; - bytes token = 2; - bytes ctoken = 3; -} - -message Connect -{ - bytes signature = 1; - bytes publickey = 2; - bytes token = 3; - bytes infostring = 4; -} +syntax = "proto3"; + +package Proto.Auth; + +message Certificate +{ + bytes privatekey = 1; + bytes token = 2; + bytes ctoken = 3; +} + +message Connect +{ + bytes signature = 1; + bytes publickey = 2; + bytes token = 3; + bytes infostring = 4; +}