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