Hello.
I would like to share a system I wrote about 5-6 years ago.
Initially it was on version 0.4, and later I moved it to 1.2 as well. During this time, it generated about 200 GB of recordings, and thanks to them, such films as https://www.youtube.com/playlist?list=PLwGkOisgt0UPKmJiNJvNp2BmQAw55Z1Bi or
(recording from a dedicated player, such as recordings generated by the system) could be created. The code is very simple and has not generated any crash since its creation, but it was tested with 20, max 30 simultaneously logged clients.
Here I am sharing it with you today, because at the same time I would like to ask if with 100+ simultaneous clients it will not load the server in any way, or if it does not have any holes through which memory may "leak"?
It is slightly better (in my opinion) than the systems presented in Feature - [TFS 1.x+] Print all send network packets in server console (https://otland.net/threads/tfs-1-x-print-all-send-network-packets-in-server-console.279699/post-2715116) or in Cam System 10.98 (TFS 1.3) (https://otland.net/threads/cam-system-10-98-tfs-1-3.265913/post-2570020), because the packets are written directly to the file, not to the server's memory, which makes it robust in case of server crash for any reason.
The structure is very similar to the BynaCam format (Google Code Archive - Long-term storage for Google Code Project Hosting. (https://code.google.com/archive/p/bynacam/source/default/source), Player.cs file, GetFileMessage method) with the difference that I store the interval between packets as delay, and timestamp was used there and the delay was calculated from the difference of timestamps.
I would like to share a system I wrote about 5-6 years ago.

Diff:
diff --git a/movies/.gitignore b/movies/.gitignore
new file mode 100644
index 00000000..1bc8d0f5
--- /dev/null
+++ b/movies/.gitignore
@@ -0,0 +1,3 @@
+*.byn
+*.cam
+!.gitignore
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 5fb09683..de7eab83 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -60,8 +60,9 @@ bool XTEA_decrypt(NetworkMessage& msg, const xtea::round_keys& key)
}
-void Protocol::onSendMessage(const OutputMessage_ptr& msg) const
+void Protocol::onSendMessage(const OutputMessage_ptr& msg)
{
+ handleMessage(msg->getOutputBuffer(), msg->getLength());
if (!rawMessages) {
msg->writeMessageLength();
@@ -111,3 +113,80 @@ uint32_t Protocol::getIP() const
return 0;
}
+
+uint8_t DELAY_ID = 0x65;
+uint8_t PACKET_ID = 0x66;
+
+void Protocol::startCam(uint32_t guid, std::string name)
+{
+ std::stringstream path;
+ path << "movies//packets_" << guid << "_" << OTSYS_TIME() << "_" << name << ".byn";
+ camPath = path.str().c_str();
+
+ if (cam) {
+ cam.close();
+ }
+
+ cam.open(camPath, std::fstream::out | std::fstream::binary | std::fstream::trunc);
+
+ if (!cam.good()) {
+ return;
+ }
+
+ camActive = 3;
+ timeLast = OTSYS_TIME();
+}
+
+void Protocol::handleMessage(const uint8_t* buffer, const uint16_t msgSize)
+{
+ if (isConnectionExpired() || camActive != 3 || !cam.good()) {
+ return;
+ }
+
+ timeNow = OTSYS_TIME();
+ uint32_t delay = timeNow - timeLast;
+ timeLast = timeNow;
+ uint32_t i;
+ uint8_t headerDelay[3] = {DELAY_ID, (uint8_t) (delay), (uint8_t) (delay >> 8)};
+
+ for (i = 0; i < 3; i++) {
+ cam.put(headerDelay[i]);
+ }
+
+ uint8_t headerPacket[3] = {PACKET_ID, (uint8_t) (msgSize), (uint8_t) (msgSize >> 8)};
+
+ for (i = 0; i < 3; i++) {
+ cam.put(headerPacket[i]);
+ }
+
+ for (i = 0; i < msgSize; i++) {
+ cam.put(buffer[i]);
+ }
+
+ cam.flush();
+}
diff --git a/src/protocol.h b/src/protocol.h
index 8bd7d6f2..e5a91fe5 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -22,6 +22,7 @@
#include "connection.h"
#include "xtea.h"
+#include <fstream>
class Protocol : public std::enable_shared_from_this<Protocol>
{
@@ -35,7 +36,7 @@ class Protocol : public std::enable_shared_from_this<Protocol>
virtual void parsePacket(NetworkMessage&) {}
- virtual void onSendMessage(const OutputMessage_ptr& msg) const;
+ virtual void onSendMessage(const OutputMessage_ptr& msg);
void onRecvMessage(NetworkMessage& msg);
virtual void onRecvFirstMessage(NetworkMessage& msg) = 0;
virtual void onConnect() {}
@@ -87,6 +88,15 @@ class Protocol : public std::enable_shared_from_this<Protocol>
virtual void release() {}
+ void startCam(uint32_t guid, std::string name);
+ void handleMessage(const uint8_t* buffer, const uint16_t msgSize);
+ std::ofstream cam;
+ int8_t camActive;
+ std::string camPath;
+ uint32_t timeLast;
+ uint32_t timeNow;
+
private:
friend class Connection;
diff --git a/src/protocolgame.cpp b/src/protocolgame.cpp
index 83fce071..8cd31ae2 100644
--- a/src/protocolgame.cpp
+++ b/src/protocolgame.cpp
@@ -234,6 +235,7 @@ void ProtocolGame::login(const std::string& name, uint32_t accountId, OperatingS
player->lastIP = player->getIP();
player->lastLoginSaved = std::max<time_t>(time(nullptr), player->lastLoginSaved + 1);
acceptPackets = true;
+ Protocol::startCam(player->getGUID(), player->getName());
} else {
if (eventConnect != 0 || !g_config.getBoolean(ConfigManager::REPLACE_KICK_ON_LOGIN)) {
//Already trying to connect
@@ -244,9 +246,11 @@ void ProtocolGame::login(const std::string& name, uint32_t accountId, OperatingS
if (foundPlayer->client) {
foundPlayer->disconnect();
foundPlayer->isConnecting = true;
+ Protocol::startCam(foundPlayer->getGUID(), foundPlayer->getName());
eventConnect = g_scheduler.addEvent(createSchedulerTask(1000, std::bind(&ProtocolGame::connect, getThis(), foundPlayer->getID(), operatingSystem)));
} else {
+ Protocol::startCam(foundPlayer->getGUID(), foundPlayer->getName());
connect(foundPlayer->getID(), operatingSystem);
}
}
Initially it was on version 0.4, and later I moved it to 1.2 as well. During this time, it generated about 200 GB of recordings, and thanks to them, such films as https://www.youtube.com/playlist?list=PLwGkOisgt0UPKmJiNJvNp2BmQAw55Z1Bi or
If I will find any information, I'll post them
Here I am sharing it with you today, because at the same time I would like to ask if with 100+ simultaneous clients it will not load the server in any way, or if it does not have any holes through which memory may "leak"?
It is slightly better (in my opinion) than the systems presented in Feature - [TFS 1.x+] Print all send network packets in server console (https://otland.net/threads/tfs-1-x-print-all-send-network-packets-in-server-console.279699/post-2715116) or in Cam System 10.98 (TFS 1.3) (https://otland.net/threads/cam-system-10-98-tfs-1-3.265913/post-2570020), because the packets are written directly to the file, not to the server's memory, which makes it robust in case of server crash for any reason.
The structure is very similar to the BynaCam format (Google Code Archive - Long-term storage for Google Code Project Hosting. (https://code.google.com/archive/p/bynacam/source/default/source), Player.cs file, GetFileMessage method) with the difference that I store the interval between packets as delay, and timestamp was used there and the delay was calculated from the difference of timestamps.