mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-07-03 08:15:35 +00:00
remove two-socket download
This commit is contained in:
parent
a4b62d013c
commit
88ca17236a
@ -66,7 +66,6 @@ public:
|
|||||||
std::string GetCarData(int Ident);
|
std::string GetCarData(int Ident);
|
||||||
std::string GetCarPositionRaw(int Ident);
|
std::string GetCarPositionRaw(int Ident);
|
||||||
void SetUDPAddr(const ip::udp::endpoint& Addr) { mUDPAddress = Addr; }
|
void SetUDPAddr(const ip::udp::endpoint& Addr) { mUDPAddress = Addr; }
|
||||||
void SetDownSock(ip::tcp::socket&& CSock) { mDownSocket = std::move(CSock); }
|
|
||||||
void SetTCPSock(ip::tcp::socket&& CSock) { mSocket = std::move(CSock); }
|
void SetTCPSock(ip::tcp::socket&& CSock) { mSocket = std::move(CSock); }
|
||||||
void Disconnect(std::string_view Reason);
|
void Disconnect(std::string_view Reason);
|
||||||
bool IsDisconnected() const { return !mSocket.is_open(); }
|
bool IsDisconnected() const { return !mSocket.is_open(); }
|
||||||
@ -75,8 +74,6 @@ public:
|
|||||||
[[nodiscard]] const std::unordered_map<std::string, std::string>& GetIdentifiers() const { return mIdentifiers; }
|
[[nodiscard]] const std::unordered_map<std::string, std::string>& GetIdentifiers() const { return mIdentifiers; }
|
||||||
[[nodiscard]] const ip::udp::endpoint& GetUDPAddr() const { return mUDPAddress; }
|
[[nodiscard]] const ip::udp::endpoint& GetUDPAddr() const { return mUDPAddress; }
|
||||||
[[nodiscard]] ip::udp::endpoint& GetUDPAddr() { return mUDPAddress; }
|
[[nodiscard]] ip::udp::endpoint& GetUDPAddr() { return mUDPAddress; }
|
||||||
[[nodiscard]] ip::tcp::socket& GetDownSock() { return mDownSocket; }
|
|
||||||
[[nodiscard]] const ip::tcp::socket& GetDownSock() const { return mDownSocket; }
|
|
||||||
[[nodiscard]] ip::tcp::socket& GetTCPSock() { return mSocket; }
|
[[nodiscard]] ip::tcp::socket& GetTCPSock() { return mSocket; }
|
||||||
[[nodiscard]] const ip::tcp::socket& GetTCPSock() const { return mSocket; }
|
[[nodiscard]] const ip::tcp::socket& GetTCPSock() const { return mSocket; }
|
||||||
[[nodiscard]] std::string GetRoles() const { return mRole; }
|
[[nodiscard]] std::string GetRoles() const { return mRole; }
|
||||||
@ -122,7 +119,6 @@ private:
|
|||||||
SparseArray<std::string> mVehiclePosition;
|
SparseArray<std::string> mVehiclePosition;
|
||||||
std::string mName = "Unknown Client";
|
std::string mName = "Unknown Client";
|
||||||
ip::tcp::socket mSocket;
|
ip::tcp::socket mSocket;
|
||||||
ip::tcp::socket mDownSocket;
|
|
||||||
ip::udp::endpoint mUDPAddress {};
|
ip::udp::endpoint mUDPAddress {};
|
||||||
int mUnicycleID = -1;
|
int mUnicycleID = -1;
|
||||||
std::string mRole;
|
std::string mRole;
|
||||||
|
@ -58,7 +58,6 @@ private:
|
|||||||
std::mutex mOpenIDMutex;
|
std::mutex mOpenIDMutex;
|
||||||
|
|
||||||
std::vector<uint8_t> UDPRcvFromClient(ip::udp::endpoint& ClientEndpoint);
|
std::vector<uint8_t> UDPRcvFromClient(ip::udp::endpoint& ClientEndpoint);
|
||||||
void HandleDownload(TConnection&& TCPSock);
|
|
||||||
void OnConnect(const std::weak_ptr<TClient>& c);
|
void OnConnect(const std::weak_ptr<TClient>& c);
|
||||||
void TCPClient(const std::weak_ptr<TClient>& c);
|
void TCPClient(const std::weak_ptr<TClient>& c);
|
||||||
void Looper(const std::weak_ptr<TClient>& c);
|
void Looper(const std::weak_ptr<TClient>& c);
|
||||||
@ -67,7 +66,7 @@ private:
|
|||||||
void Parse(TClient& c, const std::vector<uint8_t>& Packet);
|
void Parse(TClient& c, const std::vector<uint8_t>& Packet);
|
||||||
void SendFile(TClient& c, const std::string& Name);
|
void SendFile(TClient& c, const std::string& Name);
|
||||||
static bool TCPSendRaw(TClient& C, ip::tcp::socket& socket, const uint8_t* Data, size_t Size);
|
static bool TCPSendRaw(TClient& C, ip::tcp::socket& socket, const uint8_t* Data, size_t Size);
|
||||||
static void SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std::string& Name);
|
static void SendFileToClient(TClient& c, size_t Size, const std::string& Name);
|
||||||
static const uint8_t* SendSplit(TClient& c, ip::tcp::socket& Socket, const uint8_t* DataPtr, size_t Size);
|
static const uint8_t* SendSplit(TClient& c, ip::tcp::socket& Socket, const uint8_t* DataPtr, size_t Size);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -144,7 +144,6 @@ void TClient::EnqueuePacket(const std::vector<uint8_t>& Packet) {
|
|||||||
TClient::TClient(TServer& Server, ip::tcp::socket&& Socket)
|
TClient::TClient(TServer& Server, ip::tcp::socket&& Socket)
|
||||||
: mServer(Server)
|
: mServer(Server)
|
||||||
, mSocket(std::move(Socket))
|
, mSocket(std::move(Socket))
|
||||||
, mDownSocket(ip::tcp::socket(Server.IoCtx()))
|
|
||||||
, mLastPingTime(std::chrono::high_resolution_clock::now()) {
|
, mLastPingTime(std::chrono::high_resolution_clock::now()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
142
src/TNetwork.cpp
142
src/TNetwork.cpp
@ -240,7 +240,8 @@ void TNetwork::Identify(TConnection&& RawConnection) {
|
|||||||
if (Code == 'C') {
|
if (Code == 'C') {
|
||||||
Client = Authentication(std::move(RawConnection));
|
Client = Authentication(std::move(RawConnection));
|
||||||
} else if (Code == 'D') {
|
} else if (Code == 'D') {
|
||||||
HandleDownload(std::move(RawConnection));
|
beammp_errorf("Old download packet detected - the client is wildly out of date, this will be ignored");
|
||||||
|
return;
|
||||||
} else if (Code == 'P') {
|
} else if (Code == 'P') {
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
write(RawConnection.Socket, buffer("P"), ec);
|
write(RawConnection.Socket, buffer("P"), ec);
|
||||||
@ -249,7 +250,7 @@ void TNetwork::Identify(TConnection&& RawConnection) {
|
|||||||
beammp_errorf("Invalid code got in Identify: '{}'", Code);
|
beammp_errorf("Invalid code got in Identify: '{}'", Code);
|
||||||
}
|
}
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
beammp_errorf("Error during handling of code {} - client left in invalid state, closing socket", Code);
|
beammp_errorf("Error during handling of code {} - client left in invalid state, closing socket: {}", Code, e.what());
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
RawConnection.Socket.shutdown(socket_base::shutdown_both, ec);
|
RawConnection.Socket.shutdown(socket_base::shutdown_both, ec);
|
||||||
if (ec) {
|
if (ec) {
|
||||||
@ -262,27 +263,7 @@ void TNetwork::Identify(TConnection&& RawConnection) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TNetwork::HandleDownload(TConnection&& Conn) {
|
|
||||||
char D;
|
|
||||||
boost::system::error_code ec;
|
|
||||||
read(Conn.Socket, buffer(&D, 1), ec);
|
|
||||||
if (ec) {
|
|
||||||
Conn.Socket.shutdown(socket_base::shutdown_both, ec);
|
|
||||||
// ignore ec
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto ID = uint8_t(D);
|
|
||||||
mServer.ForEachClient([&](const std::weak_ptr<TClient>& ClientPtr) -> bool {
|
|
||||||
ReadLock Lock(mServer.GetClientMutex());
|
|
||||||
if (!ClientPtr.expired()) {
|
|
||||||
auto c = ClientPtr.lock();
|
|
||||||
if (c->GetID() == ID) {
|
|
||||||
c->SetDownSock(std::move(Conn.Socket));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string HashPassword(const std::string& str) {
|
std::string HashPassword(const std::string& str) {
|
||||||
std::stringstream ret;
|
std::stringstream ret;
|
||||||
@ -772,8 +753,6 @@ void TNetwork::Parse(TClient& c, const std::vector<uint8_t>& Packet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) {
|
void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) {
|
||||||
beammp_info(c.GetName() + " requesting : " + UnsafeName.substr(UnsafeName.find_last_of('/')));
|
|
||||||
|
|
||||||
if (!fs::path(UnsafeName).has_filename()) {
|
if (!fs::path(UnsafeName).has_filename()) {
|
||||||
if (!TCPSend(c, StringToVector("CO"))) {
|
if (!TCPSend(c, StringToVector("CO"))) {
|
||||||
// TODO: handle
|
// TODO: handle
|
||||||
@ -796,87 +775,9 @@ void TNetwork::SendFile(TClient& c, const std::string& UnsafeName) {
|
|||||||
// TODO: handle
|
// TODO: handle
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wait for connections
|
|
||||||
int T = 0;
|
|
||||||
while (!c.GetDownSock().is_open() && T < 50) {
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
||||||
T++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!c.GetDownSock().is_open()) {
|
|
||||||
beammp_error("Client doesn't have a download socket!");
|
|
||||||
if (!c.IsDisconnected())
|
|
||||||
c.Disconnect("Missing download socket");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Size = size_t(std::filesystem::file_size(FileName));
|
size_t Size = size_t(std::filesystem::file_size(FileName));
|
||||||
size_t MSize = Size / 2;
|
|
||||||
|
|
||||||
std::thread SplitThreads[2] {
|
SendFileToClient(c, Size, FileName);
|
||||||
std::thread([&] {
|
|
||||||
RegisterThread("SplitLoad_0");
|
|
||||||
SplitLoad(c, 0, MSize, false, FileName);
|
|
||||||
}),
|
|
||||||
std::thread([&] {
|
|
||||||
RegisterThread("SplitLoad_1");
|
|
||||||
SplitLoad(c, MSize, Size, true, FileName);
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto& SplitThread : SplitThreads) {
|
|
||||||
if (SplitThread.joinable()) {
|
|
||||||
SplitThread.join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::pair<size_t /* count */, size_t /* last chunk */> SplitIntoChunks(size_t FullSize, size_t ChunkSize) {
|
|
||||||
if (FullSize < ChunkSize) {
|
|
||||||
return { 0, FullSize };
|
|
||||||
}
|
|
||||||
size_t Count = FullSize / (FullSize / ChunkSize);
|
|
||||||
size_t LastChunkSize = FullSize - (Count * ChunkSize);
|
|
||||||
return { Count, LastChunkSize };
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("SplitIntoChunks") {
|
|
||||||
size_t FullSize;
|
|
||||||
size_t ChunkSize;
|
|
||||||
SUBCASE("Normal case") {
|
|
||||||
FullSize = 1234567;
|
|
||||||
ChunkSize = 1234;
|
|
||||||
}
|
|
||||||
SUBCASE("Zero original size") {
|
|
||||||
FullSize = 0;
|
|
||||||
ChunkSize = 100;
|
|
||||||
}
|
|
||||||
SUBCASE("Equal full size and chunk size") {
|
|
||||||
FullSize = 125;
|
|
||||||
ChunkSize = 125;
|
|
||||||
}
|
|
||||||
SUBCASE("Even split") {
|
|
||||||
FullSize = 10000;
|
|
||||||
ChunkSize = 100;
|
|
||||||
}
|
|
||||||
SUBCASE("Odd split") {
|
|
||||||
FullSize = 13;
|
|
||||||
ChunkSize = 2;
|
|
||||||
}
|
|
||||||
SUBCASE("Large sizes") {
|
|
||||||
FullSize = 10 * GB;
|
|
||||||
ChunkSize = 125 * MB;
|
|
||||||
}
|
|
||||||
auto [Count, LastSize] = SplitIntoChunks(FullSize, ChunkSize);
|
|
||||||
CHECK((Count * ChunkSize) + LastSize == FullSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t* /* end ptr */ TNetwork::SendSplit(TClient& c, ip::tcp::socket& Socket, const uint8_t* DataPtr, size_t Size) {
|
|
||||||
if (TCPSendRaw(c, Socket, DataPtr, Size)) {
|
|
||||||
return DataPtr + Size;
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(BEAMMP_LINUX)
|
#if defined(BEAMMP_LINUX)
|
||||||
@ -886,8 +787,8 @@ const uint8_t* /* end ptr */ TNetwork::SendSplit(TClient& c, ip::tcp::socket& So
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#endif
|
#endif
|
||||||
void TNetwork::SplitLoad(TClient& c, size_t Offset, size_t End, bool D, const std::string& Name) {
|
void TNetwork::SendFileToClient(TClient& c, size_t Size, const std::string& Name) {
|
||||||
TScopedTimer timer(fmt::format("Download of {}-{} for '{}'", Offset, End, Name));
|
TScopedTimer timer(fmt::format("Download of '{}' for client {}", Name, c.GetID()));
|
||||||
#if defined(BEAMMP_LINUX)
|
#if defined(BEAMMP_LINUX)
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
// on linux, we can use sendfile(2)!
|
// on linux, we can use sendfile(2)!
|
||||||
@ -897,11 +798,11 @@ void TNetwork::SplitLoad(TClient& c, size_t Offset, size_t End, bool D, const st
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// native handle, needed in order to make native syscalls with it
|
// native handle, needed in order to make native syscalls with it
|
||||||
int socket = D ? c.GetDownSock().native_handle() : c.GetTCPSock().native_handle();
|
int socket = c.GetTCPSock().native_handle();
|
||||||
|
|
||||||
ssize_t ret = 0;
|
ssize_t ret = 0;
|
||||||
auto ToSendTotal = End - Offset;
|
auto ToSendTotal = Size;
|
||||||
auto Start = Offset;
|
auto Start = 0;
|
||||||
while (ret < ssize_t(ToSendTotal)) {
|
while (ret < ssize_t(ToSendTotal)) {
|
||||||
auto SysOffset = off_t(Start + size_t(ret));
|
auto SysOffset = off_t(Start + size_t(ret));
|
||||||
ret = sendfile(socket, fd, &SysOffset, ToSendTotal - size_t(ret));
|
ret = sendfile(socket, fd, &SysOffset, ToSendTotal - size_t(ret));
|
||||||
@ -915,35 +816,32 @@ void TNetwork::SplitLoad(TClient& c, size_t Offset, size_t End, bool D, const st
|
|||||||
std::ifstream f(Name.c_str(), std::ios::binary);
|
std::ifstream f(Name.c_str(), std::ios::binary);
|
||||||
uint32_t Split = 125 * MB;
|
uint32_t Split = 125 * MB;
|
||||||
std::vector<uint8_t> Data;
|
std::vector<uint8_t> Data;
|
||||||
if (End > Split)
|
if (Size > Split)
|
||||||
Data.resize(Split);
|
Data.resize(Split);
|
||||||
else
|
else
|
||||||
Data.resize(End);
|
Data.resize(Size);
|
||||||
ip::tcp::socket* TCPSock { nullptr };
|
ip::tcp::socket* TCPSock = &c.GetTCPSock();
|
||||||
if (D)
|
std::streamsize Sent = 0;
|
||||||
TCPSock = &c.GetDownSock();
|
while (!c.IsDisconnected() && Sent < Size) {
|
||||||
else
|
size_t Diff = Size - Sent;
|
||||||
TCPSock = &c.GetTCPSock();
|
|
||||||
while (!c.IsDisconnected() && Offset < End) {
|
|
||||||
size_t Diff = End - Offset;
|
|
||||||
if (Diff > Split) {
|
if (Diff > Split) {
|
||||||
f.seekg(Offset, std::ios_base::beg);
|
f.seekg(Sent, std::ios_base::beg);
|
||||||
f.read(reinterpret_cast<char*>(Data.data()), Split);
|
f.read(reinterpret_cast<char*>(Data.data()), Split);
|
||||||
if (!TCPSendRaw(c, *TCPSock, Data.data(), Split)) {
|
if (!TCPSendRaw(c, *TCPSock, Data.data(), Split)) {
|
||||||
if (!c.IsDisconnected())
|
if (!c.IsDisconnected())
|
||||||
c.Disconnect("TCPSendRaw failed in mod download (1)");
|
c.Disconnect("TCPSendRaw failed in mod download (1)");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Offset += Split;
|
Sent += Split;
|
||||||
} else {
|
} else {
|
||||||
f.seekg(Offset, std::ios_base::beg);
|
f.seekg(Sent, std::ios_base::beg);
|
||||||
f.read(reinterpret_cast<char*>(Data.data()), Diff);
|
f.read(reinterpret_cast<char*>(Data.data()), Diff);
|
||||||
if (!TCPSendRaw(c, *TCPSock, Data.data(), int32_t(Diff))) {
|
if (!TCPSendRaw(c, *TCPSock, Data.data(), int32_t(Diff))) {
|
||||||
if (!c.IsDisconnected())
|
if (!c.IsDisconnected())
|
||||||
c.Disconnect("TCPSendRaw failed in mod download (2)");
|
c.Disconnect("TCPSendRaw failed in mod download (2)");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Offset += Diff;
|
Sent += Diff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -127,7 +127,7 @@ void TResourceManager::RefreshFiles() {
|
|||||||
}
|
}
|
||||||
beammp_debugf("sha256('{}'): {}", File, result);
|
beammp_debugf("sha256('{}'): {}", File, result);
|
||||||
mMods.push_back(nlohmann::json {
|
mMods.push_back(nlohmann::json {
|
||||||
{ "file_name", File },
|
{ "file_name", std::filesystem::path(File).filename() },
|
||||||
{ "file_size", Read },
|
{ "file_size", Read },
|
||||||
{ "hash_algorithm", "sha256" },
|
{ "hash_algorithm", "sha256" },
|
||||||
{ "hash", result },
|
{ "hash", result },
|
||||||
|
Loading…
x
Reference in New Issue
Block a user