1 /*
2 * The ManaPlus Client
3 * Copyright (C) 2004-2009 The Mana World Development Team
4 * Copyright (C) 2009-2010 The Mana Developers
5 * Copyright (C) 2011-2019 The ManaPlus Developers
6 * Copyright (C) 2019-2021 Andrei Karas
7 *
8 * This file is part of The ManaPlus Client.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "net/messagein.h"
25
26 #include "net/packetcounters.h"
27
28 #include "utils/cast.h"
29 #include "utils/stringutils.h"
30
31 #include "logger.h"
32
33 #include "debug.h"
34
35 PRAGMA48(GCC diagnostic push)
36 PRAGMA48(GCC diagnostic ignored "-Wshadow")
37 #ifndef SDL_BIG_ENDIAN
38 #include <SDL_endian.h>
39 #endif // SDL_BYTEORDER
40 PRAGMA48(GCC diagnostic pop)
41
42 #define MAKEWORD(low, high) \
43 (CAST_U16((CAST_U8(low)) | \
44 (CAST_U16(CAST_U8(high))) << 8))
45
46 extern int itemIdLen;
47 extern int packetVersionMain;
48 extern int packetVersionRe;
49 extern int packetVersionZero;
50
51 namespace Net
52 {
53
MessageIn(const char * const data,const unsigned int length)54 MessageIn::MessageIn(const char *const data,
55 const unsigned int length) :
56 mData(data),
57 mLength(length),
58 mPos(0),
59 mVersion(0),
60 mId(0),
61 mIgnore(false)
62 {
63 PacketCounters::incInPackets();
64 }
65
~MessageIn()66 MessageIn::~MessageIn()
67 {
68 if (mLength != 0U)
69 {
70 if (mPos != mLength && mPos != 2)
71 {
72 logger->log("Wrong actual or planned inbound packet size!");
73 logger->log(" packet id: %u 0x%x",
74 CAST_U32(mId),
75 CAST_U32(mId));
76 logger->log(" planned size: %u", mLength);
77 logger->log(" read size: %u", mPos);
78 WRONGPACKETSIZE;
79 }
80 }
81 else
82 {
83 logger->log("Zero packet size: %d", CAST_S32(mId));
84 }
85 }
86
readId() const87 uint16_t MessageIn::readId() const
88 {
89 int16_t value = -1;
90 if (mPos + 2 <= mLength)
91 {
92 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
93 int16_t swap;
94 memcpy(&swap, mData + CAST_SIZE(mPos), sizeof(int16_t));
95 value = SDL_Swap16(swap);
96 #else // SDL_BYTEORDER == SDL_BIG_ENDIAN
97
98 memcpy(&value, mData + CAST_SIZE(mPos), sizeof(int16_t));
99 #endif // SDL_BYTEORDER == SDL_BIG_ENDIAN
100 }
101 return value;
102 }
103
readUInt8(const char * const str)104 unsigned char MessageIn::readUInt8(const char *const str)
105 {
106 unsigned char value = CAST_U8(-1);
107 if (mPos < mLength)
108 value = CAST_U8(mData[mPos]);
109
110 DEBUGLOG2("readUInt8: " + toStringPrint(CAST_U32(value)),
111 mPos, str);
112 mPos += 1;
113 PacketCounters::incInBytes(1);
114 return value;
115 }
116
readInt8(const char * const str)117 signed char MessageIn::readInt8(const char *const str)
118 {
119 signed char value = CAST_S8(-1);
120 if (mPos < mLength)
121 value = CAST_S8(mData[mPos]);
122
123 DEBUGLOG2("readInt8: " + toStringPrint(CAST_U32(
124 CAST_U8(value))),
125 mPos, str);
126 mPos += 1;
127 PacketCounters::incInBytes(1);
128 return value;
129 }
130
readInt16(const char * const str)131 int16_t MessageIn::readInt16(const char *const str)
132 {
133 int16_t value = -1;
134 if (mPos + 2 <= mLength)
135 {
136 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
137 int16_t swap;
138 memcpy(&swap, mData + CAST_SIZE(mPos), sizeof(int16_t));
139 value = SDL_Swap16(swap);
140 #else // SDL_BYTEORDER == SDL_BIG_ENDIAN
141
142 memcpy(&value, mData + CAST_SIZE(mPos), sizeof(int16_t));
143 #endif // SDL_BYTEORDER == SDL_BIG_ENDIAN
144 }
145 DEBUGLOG2("readInt16: " + toStringPrint(CAST_U32(
146 CAST_U16(value))),
147 mPos, str);
148 mPos += 2;
149 PacketCounters::incInBytes(2);
150 return value;
151 }
152
readUInt16(const char * const str)153 uint16_t MessageIn::readUInt16(const char *const str)
154 {
155 uint16_t value = 0xffU;
156 if (mPos + 2 <= mLength)
157 {
158 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
159 uint16_t swap;
160 memcpy(&swap, mData + CAST_SIZE(mPos), sizeof(uint16_t));
161 value = SDL_Swap16(swap);
162 #else // SDL_BYTEORDER == SDL_BIG_ENDIAN
163
164 memcpy(&value, mData + CAST_SIZE(mPos), sizeof(uint16_t));
165 #endif // SDL_BYTEORDER == SDL_BIG_ENDIAN
166 }
167 DEBUGLOG2("readUInt16: " + toStringPrint(CAST_U32(
168 CAST_U16(value))),
169 mPos, str);
170 mPos += 2;
171 PacketCounters::incInBytes(2);
172 return value;
173 }
174
readInt32(const char * const str)175 int32_t MessageIn::readInt32(const char *const str)
176 {
177 int32_t value = -1;
178 if (mPos + 4 <= mLength)
179 {
180 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
181 int32_t swap;
182 memcpy(&swap, mData + CAST_SIZE(mPos), sizeof(int32_t));
183 value = SDL_Swap32(swap);
184 #else // SDL_BYTEORDER == SDL_BIG_ENDIAN
185
186 memcpy(&value, mData + CAST_SIZE(mPos), sizeof(int32_t));
187 #endif // SDL_BYTEORDER == SDL_BIG_ENDIAN
188 }
189 DEBUGLOG2("readInt32: " + toStringPrint(CAST_S32(value)),
190 mPos, str);
191 mPos += 4;
192 PacketCounters::incInBytes(4);
193 return value;
194 }
195
readUInt32(const char * const str)196 uint32_t MessageIn::readUInt32(const char *const str)
197 {
198 uint32_t value = 0;
199 if (mPos + 4 <= mLength)
200 {
201 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
202 uint32_t swap;
203 memcpy(&swap, mData + CAST_SIZE(mPos), sizeof(int32_t));
204 value = SDL_Swap32(swap);
205 #else // SDL_BYTEORDER == SDL_BIG_ENDIAN
206
207 memcpy(&value, mData + CAST_SIZE(mPos), sizeof(int32_t));
208 #endif // SDL_BYTEORDER == SDL_BIG_ENDIAN
209 }
210 DEBUGLOG2("readInt32: " + toStringPrint(CAST_U32(value)),
211 mPos, str);
212 mPos += 4;
213 PacketCounters::incInBytes(4);
214 return value;
215 }
216
readItemId(const char * const str)217 int MessageIn::readItemId(const char *const str)
218 {
219 if (itemIdLen == 2)
220 return readInt16(str);
221 return readInt32(str);
222 }
223
readBeingId(const char * const str)224 BeingId MessageIn::readBeingId(const char *const str)
225 {
226 return fromInt(readUInt32(str), BeingId);
227 }
228
readInt64(const char * const str)229 int64_t MessageIn::readInt64(const char *const str)
230 {
231 int64_t value = -1;
232 if (mPos + 8 <= mLength)
233 {
234 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
235 int64_t swap;
236 memcpy(&swap, mData + CAST_SIZE(mPos), sizeof(int64_t));
237 value = SDL_Swap64(swap);
238 #else // SDL_BYTEORDER == SDL_BIG_ENDIAN
239
240 memcpy(&value, mData + CAST_SIZE(mPos), sizeof(int64_t));
241 #endif // SDL_BYTEORDER == SDL_BIG_ENDIAN
242 }
243 DEBUGLOG2("readInt64: " + toStringPrint(CAST_U32(value)),
244 mPos, str);
245 mPos += 8;
246 PacketCounters::incInBytes(8);
247 return value;
248 }
249
readFloat(const char * const str)250 float MessageIn::readFloat(const char *const str)
251 {
252 float value = 0;
253 if (mPos + 4 <= mLength)
254 {
255 memcpy(&value, mData + CAST_SIZE(mPos), sizeof(float));
256 }
257 #ifdef ENABLEDEBUGLOG
258 std::string text = strprintf("readFloat: %f", value);
259 DEBUGLOG2(str, mPos, text.c_str());
260 #endif
261 mPos += 4;
262 PacketCounters::incInBytes(4);
263 return value;
264 }
265
fromServerDirection(const uint8_t serverDir)266 uint8_t MessageIn::fromServerDirection(const uint8_t serverDir)
267 {
268 // Translate from eAthena format
269 switch (serverDir)
270 {
271 case 0:
272 return 1;
273 case 1:
274 return 3;
275 case 2:
276 return 2;
277 case 3:
278 return 6;
279 case 4:
280 return 4;
281 case 5:
282 return 12;
283 case 6:
284 return 8;
285 case 7:
286 return 9;
287 case 8:
288 return 8;
289 default:
290 logger->log("incorrect direction: %d",
291 CAST_S32(serverDir));
292 return 0;
293 }
294 }
295
readCoordinates(uint16_t & restrict x,uint16_t & restrict y,uint8_t & restrict direction,const char * const str)296 void MessageIn::readCoordinates(uint16_t &restrict x,
297 uint16_t &restrict y,
298 uint8_t &restrict direction,
299 const char *const str)
300 {
301 if (mPos + 3 <= mLength)
302 {
303 const char *const data = mData + CAST_SIZE(mPos);
304 uint16_t temp = MAKEWORD(data[1] & 0x00c0, data[0] & 0x00ff);
305 x = CAST_U16(temp >> 6);
306 temp = MAKEWORD(data[2] & 0x00f0, data[1] & 0x003f);
307 y = CAST_U16(temp >> 4);
308
309 const uint8_t serverDir = CAST_U8(data[2] & 0x000f);
310 direction = fromServerDirection(serverDir);
311
312 DEBUGLOG2(std::string("readCoordinates: ").append(toString(
313 CAST_S32(x))).append(",").append(toString(
314 CAST_S32(y))).append(",").append(toString(
315 CAST_S32(serverDir))), mPos, str);
316 }
317 else
318 {
319 x = 0;
320 y = 0;
321 direction = 0;
322 logger->log("error: wrong readCoordinates packet");
323 }
324 mPos += 3;
325 PacketCounters::incInBytes(3);
326 }
327
readCoordinatePair(uint16_t & restrict srcX,uint16_t & restrict srcY,uint16_t & restrict dstX,uint16_t & restrict dstY,const char * const str)328 void MessageIn::readCoordinatePair(uint16_t &restrict srcX,
329 uint16_t &restrict srcY,
330 uint16_t &restrict dstX,
331 uint16_t &restrict dstY,
332 const char *const str)
333 {
334 if (mPos + 5 <= mLength)
335 {
336 const char *const data = mData + CAST_SIZE(mPos);
337 uint16_t temp = MAKEWORD(data[3], data[2] & 0x000f);
338 dstX = CAST_U16(temp >> 2);
339
340 dstY = MAKEWORD(data[4], data[3] & 0x0003);
341
342 temp = MAKEWORD(data[1], data[0]);
343 srcX = CAST_U16(temp >> 6);
344
345 temp = MAKEWORD(data[2], data[1] & 0x003f);
346 srcY = CAST_U16(temp >> 4);
347
348 DEBUGLOG2(std::string("readCoordinatePair: ").append(toString(
349 CAST_S32(srcX))).append(",").append(toString(
350 CAST_S32(srcY))).append(" ").append(toString(
351 CAST_S32(dstX))).append(",").append(toString(
352 CAST_S32(dstY))), mPos, str);
353 }
354 else
355 {
356 srcX = 0;
357 srcY = 0;
358 dstX = 0;
359 dstY = 0;
360 logger->log("error: wrong readCoordinatePair packet");
361 }
362 mPos += 5;
363 PacketCounters::incInBytes(5);
364 }
365
skip(const unsigned int length,const char * const str)366 void MessageIn::skip(const unsigned int length, const char *const str)
367 {
368 DEBUGLOG2("skip: " + toString(CAST_S32(length)), mPos, str);
369 mPos += length;
370 PacketCounters::incInBytes(length);
371 }
372
skipToEnd(const char * const str)373 void MessageIn::skipToEnd(const char *const str)
374 {
375 const int diff = CAST_S32(mLength - mPos);
376 if (diff != 0)
377 {
378 DEBUGLOG2("skip: " + toString(diff), mPos, str);
379 mPos = mLength;
380 PacketCounters::incInBytes(diff);
381 }
382 }
383
readString(int length,const char * const dstr)384 std::string MessageIn::readString(int length, const char *const dstr)
385 {
386 // Get string length
387 if (length < 0)
388 length = readInt16("len");
389
390 // Make sure the string isn't erroneous
391 if (length < 0 || mPos + length > mLength)
392 {
393 DEBUGLOG2("readString error", mPos, dstr);
394 mPos = mLength + 1;
395 return "";
396 }
397
398 // Read the string
399 const char *const stringBeg = mData + CAST_SIZE(mPos);
400 const char *const stringEnd
401 = static_cast<const char *>(memchr(stringBeg, '\0', length));
402
403 const std::string str(stringBeg, stringEnd != nullptr
404 ? stringEnd - stringBeg : CAST_SIZE(length));
405 DEBUGLOG2("readString: " + str, mPos, dstr);
406 mPos += length;
407 PacketCounters::incInBytes(length);
408 return str;
409 }
410
readRawString(int length,const char * const dstr)411 std::string MessageIn::readRawString(int length, const char *const dstr)
412 {
413 // Get string length
414 if (length < 0)
415 length = readInt16("len");
416
417 // Make sure the string isn't erroneous
418 if (length < 0 || mPos + length > mLength)
419 {
420 mPos = mLength + 1;
421 return "";
422 }
423
424 // Read the string
425 const char *const stringBeg = mData + CAST_SIZE(mPos);
426 const char *const stringEnd
427 = static_cast<const char *>(memchr(stringBeg, '\0', length));
428 std::string str(stringBeg, stringEnd != nullptr
429 ? stringEnd - stringBeg : CAST_SIZE(length));
430
431 DEBUGLOG2("readString: " + str, mPos, dstr);
432
433 if (stringEnd != nullptr)
434 {
435 const size_t len2 = CAST_SIZE(length)
436 - (stringEnd - stringBeg) - 1;
437 const char *const stringBeg2 = stringEnd + 1;
438 const char *const stringEnd2
439 = static_cast<const char *>(memchr(stringBeg2, '\0', len2));
440 const std::string hiddenPart = std::string(stringBeg2,
441 stringEnd2 != nullptr ? stringEnd2 - stringBeg2 : len2);
442 if (hiddenPart.length() > 0)
443 {
444 DEBUGLOG2("readString2: " + hiddenPart, mPos, dstr);
445 return str.append("|").append(hiddenPart);
446 }
447 }
448 mPos += length;
449 PacketCounters::incInBytes(length);
450
451 return str;
452 }
453
readBytes(int length,const char * const dstr)454 unsigned char *MessageIn::readBytes(int length, const char *const dstr)
455 {
456 // Get string length
457 if (length < 0)
458 length = readInt16("len");
459
460 // Make sure the string isn't erroneous
461 if (length < 0 || mPos + length > mLength)
462 {
463 DEBUGLOG2("readBytesString error", mPos, dstr);
464 mPos = mLength + 1;
465 return nullptr;
466 }
467
468 unsigned char *const buf
469 = new unsigned char[CAST_SIZE(length + 2)];
470
471 memcpy(buf, mData + CAST_SIZE(mPos), length);
472 buf[length] = 0;
473 buf[length + 1] = 0;
474 mPos += length;
475
476 #ifdef ENABLEDEBUGLOG
477 if (!mIgnore)
478 {
479 std::string str;
480 for (int f = 0; f < length; f ++)
481 str.append(strprintf("%02x", CAST_U32(buf[f])));
482 str += " ";
483 for (int f = 0; f < length; f ++)
484 {
485 if (buf[f] != 0U)
486 str.append(strprintf("%c", buf[f]));
487 else
488 str.append("_");
489 }
490 if (dstr != nullptr)
491 logger->dlog(dstr);
492 logger->dlog("ReadBytes: " + str);
493 }
494 #endif // ENABLEDEBUGLOG
495
496 PacketCounters::incInBytes(length);
497 return buf;
498 }
499
getVersionMain() const500 int MessageIn::getVersionMain() const noexcept2
501 {
502 if (packetVersionMain >= mVersion)
503 return mVersion;
504 return 0;
505 }
506
getVersionRe() const507 int MessageIn::getVersionRe() const noexcept2
508 {
509 if (packetVersionRe >= mVersion)
510 return mVersion;
511 return 0;
512 }
513
getVersionZero() const514 int MessageIn::getVersionZero() const noexcept2
515 {
516 if (packetVersionZero >= mVersion)
517 return mVersion;
518 return 0;
519 }
520
521 } // namespace Net
522