ManaPlus
messagein.cpp
Go to the documentation of this file.
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 
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 {
64 }
65 
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);
79  }
80  }
81  else
82  {
83  logger->log("Zero packet size: %d", CAST_S32(mId));
84  }
85 }
86 
87 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 
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;
114  return value;
115 }
116 
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;
128  return value;
129 }
130 
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;
150  return value;
151 }
152 
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;
172  return value;
173 }
174 
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;
193  return value;
194 }
195 
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;
214  return value;
215 }
216 
217 int MessageIn::readItemId(const char *const str)
218 {
219  if (itemIdLen == 2)
220  return readInt16(str);
221  return readInt32(str);
222 }
223 
224 BeingId MessageIn::readBeingId(const char *const str)
225 {
226  return fromInt(readUInt32(str), BeingId);
227 }
228 
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;
247  return value;
248 }
249 
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;
263  return value;
264 }
265 
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 
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;
326 }
327 
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;
364 }
365 
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;
371 }
372 
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;
381  }
382 }
383 
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;
408  return str;
409 }
410 
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;
450 
451  return str;
452 }
453 
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 
497  return buf;
498 }
499 
501 {
503  return mVersion;
504  return 0;
505 }
506 
508 {
509  if (packetVersionRe >= mVersion)
510  return mVersion;
511  return 0;
512 }
513 
515 {
517  return mVersion;
518  return 0;
519 }
520 
521 } // namespace Net
int BeingId
Definition: beingid.h:30
#define CAST_U16
Definition: cast.h:29
#define CAST_S8
Definition: cast.h:26
#define CAST_S32
Definition: cast.h:30
#define CAST_U32
Definition: cast.h:31
#define CAST_SIZE
Definition: cast.h:34
#define CAST_U8
Definition: cast.h:27
void log(const char *const log_text,...)
Definition: logger.cpp:269
void dlog(const std::string &str)
Definition: logger.cpp:148
unsigned int mPos
Definition: messagein.h:159
uint32_t readUInt32(const char *const str)
Definition: messagein.cpp:196
uint16_t mId
Definition: messagein.h:161
int getVersionZero() const
Definition: messagein.cpp:514
int64_t readInt64(const char *const str)
Definition: messagein.cpp:229
int getVersionRe() const
Definition: messagein.cpp:507
float readFloat(const char *const str)
Definition: messagein.cpp:250
void readCoordinatePair(uint16_t &srcX, uint16_t &srcY, uint16_t &dstX, uint16_t &dstY, const char *const str)
Definition: messagein.cpp:328
int32_t readInt32(const char *const str)
Definition: messagein.cpp:175
signed char readInt8(const char *const str)
Definition: messagein.cpp:117
void skip(const unsigned int length, const char *const str)
Definition: messagein.cpp:366
uint16_t readUInt16(const char *const str)
Definition: messagein.cpp:153
unsigned int mLength
Definition: messagein.h:152
MessageIn(const char *const data, const unsigned int length)
Definition: messagein.cpp:54
int16_t readInt16(const char *const str)
Definition: messagein.cpp:131
BeingId readBeingId(const char *const str)
Definition: messagein.cpp:224
std::string readString(int length, const char *const dstr)
Definition: messagein.cpp:384
unsigned char readUInt8(const char *const str)
Definition: messagein.cpp:104
static uint8_t fromServerDirection(const uint8_t serverDir)
Definition: messagein.cpp:266
unsigned char * readBytes(int length, const char *const dstr)
Definition: messagein.cpp:454
const char * mData
Definition: messagein.h:151
std::string readRawString(int length, const char *const dstr)
Definition: messagein.cpp:411
uint16_t readId() const
Definition: messagein.cpp:87
void readCoordinates(uint16_t &x, uint16_t &y, uint8_t &direction, const char *const str)
Definition: messagein.cpp:296
virtual ~MessageIn()
Definition: messagein.cpp:66
int getVersionMain() const
Definition: messagein.cpp:500
int readItemId(const char *const str)
Definition: messagein.cpp:217
void skipToEnd(const char *const str)
Definition: messagein.cpp:373
static void incInBytes(const int cnt)
static void incInPackets()
#define fromInt(val, name)
Definition: intdefines.h:46
#define restrict
Definition: localconsts.h:165
#define noexcept2
Definition: localconsts.h:50
#define PRAGMA48(str)
Definition: localconsts.h:199
Logger * logger
Definition: logger.cpp:89
#define WRONGPACKETSIZE
Definition: logger.h:62
#define DEBUGLOG2(str, pos, comment)
Definition: logger.h:42
uint32_t data
int itemIdLen
Definition: client.cpp:130
int packetVersionRe
Definition: client.cpp:127
int packetVersionMain
Definition: client.cpp:126
#define MAKEWORD(low, high)
Definition: messagein.cpp:42
int packetVersionZero
Definition: client.cpp:128
std::string toString(T const &value)
converts any type to a string
Definition: catch.hpp:1774
PlayerInfoBackend mData
Definition: playerinfo.cpp:56
std::string toStringPrint(const unsigned int val)
std::string strprintf(const char *const format,...)