1/**
2 * The Forgotten Server - a free and open-source MMORPG server emulator
3 * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#ifndef FS_OUTPUTMESSAGE_H_C06AAED85C7A43939F22D229297C0CC1
21#define FS_OUTPUTMESSAGE_H_C06AAED85C7A43939F22D229297C0CC1
22
23#include "networkmessage.h"
24#include "connection.h"
25#include "tools.h"
26
27class Protocol;
28
29class OutputMessage : public NetworkMessage
30{
31 public:
32 OutputMessage() = default;
33
34 // non-copyable
35 OutputMessage(const OutputMessage&) = delete;
36 OutputMessage& operator=(const OutputMessage&) = delete;
37
38 uint8_t* getOutputBuffer() {
39 return buffer + outputBufferStart;
40 }
41
42 void writeMessageLength() {
43 add_header(info.length);
44 }
45
46 void addCryptoHeader(bool addChecksum, bool compression = false) {
47 if (compression) {
48 add_header<uint32_t>(0);
49 } else if (addChecksum) {
50 add_header(adlerChecksum(buffer + outputBufferStart, info.length));
51 }
52
53 writeMessageLength();
54 }
55
56 void append(const NetworkMessage& msg) {
57 auto msgLen = msg.getLength();
58 memcpy(buffer + info.position, msg.getBuffer() + 8, msgLen);
59 info.length += msgLen;
60 info.position += msgLen;
61 }
62
63 void append(const OutputMessage_ptr& msg) {
64 auto msgLen = msg->getLength();
65 memcpy(buffer + info.position, msg->getBuffer() + 8, msgLen);
66 info.length += msgLen;
67 info.position += msgLen;
68 }
69
70 private:
71 template <typename T>
72 void add_header(T add) {
73 assert(outputBufferStart >= sizeof(T));
74 outputBufferStart -= sizeof(T);
75 memcpy(buffer + outputBufferStart, &add, sizeof(T));
76 //added header size to the message size
77 info.length += sizeof(T);
78 }
79
80 MsgSize_t outputBufferStart = INITIAL_BUFFER_POSITION;
81};
82
83class OutputMessagePool
84{
85 public:
86 // non-copyable
87 OutputMessagePool(const OutputMessagePool&) = delete;
88 OutputMessagePool& operator=(const OutputMessagePool&) = delete;
89
90 static OutputMessagePool& getInstance() {
91 static OutputMessagePool instance;
92 return instance;
93 }
94
95 void sendAll();
96 void scheduleSendAll();
97
98 static OutputMessage_ptr getOutputMessage();
99
100 void addProtocolToAutosend(Protocol_ptr protocol);
101 void removeProtocolFromAutosend(const Protocol_ptr& protocol);
102 private:
103 OutputMessagePool() = default;
104 //NOTE: A vector is used here because this container is mostly read
105 //and relatively rarely modified (only when a client connects/disconnects)
106 std::vector<Protocol_ptr> bufferedProtocols;
107};
108
109
110#endif
111