GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/net/packetlimiter.cpp Lines: 0 118 0.0 %
Date: 2021-03-17 Branches: 0 86 0.0 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2011-2019  The ManaPlus Developers
4
 *  Copyright (C) 2019-2021  Andrei Karas
5
 *
6
 *  This file is part of The ManaPlus Client.
7
 *
8
 *  This program is free software; you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation; either version 2 of the License, or
11
 *  any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
#include "net/packetlimiter.h"
23
24
#include "configuration.h"
25
#include "settings.h"
26
27
#include "utils/cast.h"
28
#include "utils/checkutils.h"
29
#include "utils/timer.h"
30
31
#include <fstream>
32
#include <sys/stat.h>
33
34
#include "debug.h"
35
36
struct PacketLimit final
37
{
38
    A_DEFAULT_COPY(PacketLimit)
39
40
    int lastTime;
41
    int timeLimit;
42
    int cnt;
43
    int cntLimit;
44
};
45
46
PacketLimit mPacketLimits[CAST_SIZE(PacketType::PACKET_SIZE) + 1];
47
48
void PacketLimiter::initPacketLimiter()
49
{
50
    // here i setting packet limits. but current server is broken,
51
    // and this limits may not help.
52
53
    mPacketLimits[CAST_SIZE(
54
        PacketType::PACKET_CHAT)].timeLimit = 10 + 5;
55
    mPacketLimits[CAST_SIZE(
56
        PacketType::PACKET_CHAT)].lastTime = 0;
57
    mPacketLimits[CAST_SIZE(
58
        PacketType::PACKET_CHAT)].cntLimit = 1;
59
    mPacketLimits[CAST_SIZE(
60
        PacketType::PACKET_CHAT)].cnt = 0;
61
62
    // 10
63
    mPacketLimits[CAST_SIZE(
64
        PacketType::PACKET_PICKUP)].timeLimit = 10 + 5;
65
    mPacketLimits[CAST_SIZE(
66
        PacketType::PACKET_PICKUP)].lastTime = 0;
67
    mPacketLimits[CAST_SIZE(
68
        PacketType::PACKET_PICKUP)].cntLimit = 1;
69
    mPacketLimits[CAST_SIZE(
70
        PacketType::PACKET_PICKUP)].cnt = 0;
71
72
    // 10 5
73
    mPacketLimits[CAST_SIZE(
74
        PacketType::PACKET_DROP)].timeLimit = 5;
75
    mPacketLimits[CAST_SIZE(
76
        PacketType::PACKET_DROP)].lastTime = 0;
77
    mPacketLimits[CAST_SIZE(
78
        PacketType::PACKET_DROP)].cntLimit = 1;
79
    mPacketLimits[CAST_SIZE(
80
        PacketType::PACKET_DROP)].cnt = 0;
81
82
    // 100
83
    mPacketLimits[CAST_SIZE(
84
        PacketType::PACKET_NPC_NEXT)].timeLimit = 0;
85
    mPacketLimits[CAST_SIZE(
86
        PacketType::PACKET_NPC_NEXT)].lastTime = 0;
87
    mPacketLimits[CAST_SIZE(
88
        PacketType::PACKET_NPC_NEXT)].cntLimit = 1;
89
    mPacketLimits[CAST_SIZE(
90
        PacketType::PACKET_NPC_NEXT)].cnt = 0;
91
92
    mPacketLimits[CAST_SIZE(
93
        PacketType::PACKET_NPC_INPUT)].timeLimit = 100;
94
    mPacketLimits[CAST_SIZE(
95
        PacketType::PACKET_NPC_INPUT)].lastTime = 0;
96
    mPacketLimits[CAST_SIZE(
97
        PacketType::PACKET_NPC_INPUT)].cntLimit = 1;
98
    mPacketLimits[CAST_SIZE(
99
        PacketType::PACKET_NPC_INPUT)].cnt = 0;
100
101
    // 50
102
    mPacketLimits[CAST_SIZE(
103
        PacketType::PACKET_NPC_TALK)].timeLimit = 60;
104
    mPacketLimits[CAST_SIZE(
105
        PacketType::PACKET_NPC_TALK)].lastTime = 0;
106
    mPacketLimits[CAST_SIZE(
107
        PacketType::PACKET_NPC_TALK)].cntLimit = 1;
108
    mPacketLimits[CAST_SIZE(
109
        PacketType::PACKET_NPC_TALK)].cnt = 0;
110
111
    // 10
112
    mPacketLimits[CAST_SIZE(
113
        PacketType::PACKET_EMOTE)].timeLimit = 10 + 5;
114
    mPacketLimits[CAST_SIZE(
115
        PacketType::PACKET_EMOTE)].lastTime = 0;
116
    mPacketLimits[CAST_SIZE(
117
        PacketType::PACKET_EMOTE)].cntLimit = 1;
118
    mPacketLimits[CAST_SIZE(
119
        PacketType::PACKET_EMOTE)].cnt = 0;
120
121
    // 100
122
    mPacketLimits[CAST_SIZE(
123
        PacketType::PACKET_SIT)].timeLimit = 100;
124
    mPacketLimits[CAST_SIZE(
125
        PacketType::PACKET_SIT)].lastTime = 0;
126
    mPacketLimits[CAST_SIZE(
127
        PacketType::PACKET_SIT)].cntLimit = 1;
128
    mPacketLimits[CAST_SIZE(
129
        PacketType::PACKET_SIT)].cnt = 0;
130
131
    mPacketLimits[CAST_SIZE(
132
        PacketType::PACKET_DIRECTION)].timeLimit = 50;
133
    mPacketLimits[CAST_SIZE(
134
        PacketType::PACKET_DIRECTION)].lastTime = 0;
135
    mPacketLimits[CAST_SIZE(
136
        PacketType::PACKET_DIRECTION)].cntLimit = 1;
137
    mPacketLimits[CAST_SIZE(
138
        PacketType::PACKET_DIRECTION)].cnt = 0;
139
140
    // 2+
141
    mPacketLimits[CAST_SIZE(
142
        PacketType::PACKET_ATTACK)].timeLimit = 2 + 10;
143
    mPacketLimits[CAST_SIZE(
144
        PacketType::PACKET_ATTACK)].lastTime = 0;
145
    mPacketLimits[CAST_SIZE(
146
        PacketType::PACKET_ATTACK)].cntLimit = 1;
147
    mPacketLimits[CAST_SIZE(
148
        PacketType::PACKET_ATTACK)].cnt = 0;
149
150
    mPacketLimits[CAST_SIZE(
151
        PacketType::PACKET_STOPATTACK)].timeLimit = 2 + 10;
152
    mPacketLimits[CAST_SIZE(
153
        PacketType::PACKET_STOPATTACK)].lastTime = 0;
154
    mPacketLimits[CAST_SIZE(
155
        PacketType::PACKET_STOPATTACK)].cntLimit = 1;
156
    mPacketLimits[CAST_SIZE(
157
        PacketType::PACKET_STOPATTACK)].cnt = 0;
158
159
    mPacketLimits[CAST_SIZE(
160
        PacketType::PACKET_ONLINELIST)].timeLimit = 1800;
161
    mPacketLimits[CAST_SIZE(
162
        PacketType::PACKET_ONLINELIST)].lastTime = 0;
163
    mPacketLimits[CAST_SIZE(
164
        PacketType::PACKET_ONLINELIST)].cntLimit = 1;
165
    mPacketLimits[CAST_SIZE(
166
        PacketType::PACKET_ONLINELIST)].cnt = 0;
167
168
    // 300ms + 50 fix
169
    mPacketLimits[CAST_SIZE(
170
        PacketType::PACKET_WHISPER)].timeLimit = 30 + 5;
171
    mPacketLimits[CAST_SIZE(
172
        PacketType::PACKET_WHISPER)].lastTime = 0;
173
    mPacketLimits[CAST_SIZE(
174
        PacketType::PACKET_WHISPER)].cntLimit = 1;
175
    mPacketLimits[CAST_SIZE(
176
        PacketType::PACKET_WHISPER)].cnt = 0;
177
178
    if (!settings.serverConfigDir.empty())
179
    {
180
        const std::string packetLimitsName = settings.serverConfigDir
181
            + "/packetlimiter.txt";
182
183
        std::ifstream inPacketFile;
184
        struct stat statbuf;
185
186
        if ((stat(packetLimitsName.c_str(), &statbuf) != 0)
187
            || !S_ISREG(statbuf.st_mode))
188
        {
189
            // wtiting new file
190
            writePacketLimits(packetLimitsName);
191
        }
192
        else
193
        {   // reading existent file
194
            inPacketFile.open(packetLimitsName.c_str(), std::ios::in);
195
            char line[101];
196
197
            if (!inPacketFile.is_open() || !inPacketFile.getline(line, 100))
198
            {
199
                inPacketFile.close();
200
                return;
201
            }
202
203
            const int ver = atoi(line);
204
205
            for (int f = 0;
206
                 f < CAST_S32(PacketType::PACKET_SIZE);
207
                 f ++)
208
            {
209
                if (!inPacketFile.getline(line, 100))
210
                    break;
211
212
                if (!(ver == 1 &&
213
                    (static_cast<PacketTypeT>(f) == PacketType::PACKET_DROP ||
214
                    static_cast<PacketTypeT>(f)
215
                    == PacketType::PACKET_NPC_NEXT)))
216
                {
217
                    mPacketLimits[f].timeLimit = atoi(line);
218
                }
219
            }
220
            inPacketFile.close();
221
            if (ver < 5)
222
                writePacketLimits(packetLimitsName);
223
        }
224
    }
225
}
226
227
void PacketLimiter::writePacketLimits(const std::string &packetLimitsName)
228
{
229
    std::ofstream outPacketFile;
230
    outPacketFile.open(packetLimitsName.c_str(), std::ios::out);
231
    if (!outPacketFile.is_open())
232
    {
233
        reportAlways("Error opening file for writing: %s",
234
            packetLimitsName.c_str())
235
        outPacketFile.close();
236
        return;
237
    }
238
    outPacketFile << "4" << std::endl;
239
    for (int f = 0; f < CAST_S32(PacketType::PACKET_SIZE); f ++)
240
    {
241
        outPacketFile << toString(mPacketLimits[f].timeLimit)
242
                      << std::endl;
243
    }
244
245
    outPacketFile.close();
246
}
247
248
bool PacketLimiter::checkPackets(const PacketTypeT type)
249
{
250
    if (type > PacketType::PACKET_SIZE)
251
        return false;
252
253
    if (!serverConfig.getValueBool("enableBuggyServers", true))
254
        return true;
255
256
    const PacketLimit &limit = mPacketLimits[CAST_SIZE(type)];
257
    const int timeLimit = limit.timeLimit;
258
259
    if (timeLimit == 0)
260
        return true;
261
262
    const int time = tick_time;
263
    const int lastTime = limit.lastTime;
264
    const int cnt = limit.cnt;
265
    const int cntLimit = limit.cntLimit;
266
267
    if (lastTime > tick_time)
268
    {
269
//        instance()->mPacketLimits[type].lastTime = time;
270
//        instance()->mPacketLimits[type].cnt = 0;
271
272
        return true;
273
    }
274
    else if (lastTime + timeLimit > time)
275
    {
276
        if (cnt >= cntLimit)
277
        {
278
            return false;
279
        }
280
//        instance()->mPacketLimits[type].cnt ++;
281
        return true;
282
    }
283
//    instance()->mPacketLimits[type].lastTime = time;
284
//    instance()->mPacketLimits[type].cnt = 1;
285
    return true;
286
}
287
288
bool PacketLimiter::limitPackets(const PacketTypeT type)
289
{
290
    if (CAST_S32(type) < 0 || type > PacketType::PACKET_SIZE)
291
        return false;
292
293
    if (!serverConfig.getValueBool("enableBuggyServers", true))
294
        return true;
295
296
    PacketLimit &pack = mPacketLimits[CAST_SIZE(type)];
297
    const int timeLimit = pack.timeLimit;
298
299
    if (timeLimit == 0)
300
        return true;
301
302
    const int time = tick_time;
303
    const int lastTime = pack.lastTime;
304
    const int cnt = pack.cnt;
305
    const int cntLimit = pack.cntLimit;
306
307
    if (lastTime > tick_time)
308
    {
309
        pack.lastTime = time;
310
        pack.cnt = 0;
311
        return true;
312
    }
313
    else if (lastTime + timeLimit > time)
314
    {
315
        if (cnt >= cntLimit)
316
        {
317
            return false;
318
        }
319
        pack.cnt ++;
320
        return true;
321
    }
322
    pack.lastTime = time;
323
    pack.cnt = 1;
324
    return true;
325
}