Skip to content

Commit 72d8a56

Browse files
glebmAJenbo
authored andcommitted
Big-endian networking fixes
1 parent fb625d8 commit 72d8a56

File tree

9 files changed

+91
-56
lines changed

9 files changed

+91
-56
lines changed

Source/DiabloUI/multi/selgame.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,9 @@ void selgame_Password_Select(int /*value*/)
660660
m_game_data->bTheoQuest = *sgOptions.Gameplay.theoQuest ? 1 : 0;
661661
m_game_data->bCowQuest = *sgOptions.Gameplay.cowQuest ? 1 : 0;
662662

663-
if (SNetCreateGame(nullptr, gamePassword, (char *)m_game_data, sizeof(*m_game_data), gdwPlayerId)) {
663+
GameData gameInitInfo = *m_game_data;
664+
gameInitInfo.swapLE();
665+
if (SNetCreateGame(nullptr, gamePassword, reinterpret_cast<char *>(&gameInitInfo), sizeof(gameInitInfo), gdwPlayerId)) {
664666
UiInitList_clear();
665667
selgame_endMenu = true;
666668
} else {

Source/dvlnet/base.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ bool base::SNetRegisterEventHandler(event_type evtype, SEVTHANDLER func)
401401
bool base::SNetLeaveGame(int type)
402402
{
403403
auto pkt = pktfty->make_packet<PT_DISCONNECT>(plr_self, PLR_BROADCAST,
404-
plr_self, type);
404+
plr_self, static_cast<leaveinfo_t>(type));
405405
send(*pkt);
406406
plr_self = PLR_BROADCAST;
407407
return true;
@@ -411,8 +411,8 @@ bool base::SNetDropPlayer(int playerid, uint32_t flags)
411411
{
412412
auto pkt = pktfty->make_packet<PT_DISCONNECT>(plr_self,
413413
PLR_BROADCAST,
414-
(plr_t)playerid,
415-
(leaveinfo_t)flags);
414+
static_cast<plr_t>(playerid),
415+
static_cast<leaveinfo_t>(flags));
416416
send(*pkt);
417417
RecvLocal(*pkt);
418418
return true;

Source/dvlnet/base_protocol.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,10 @@ void base_protocol<P>::recv_decrypted(packet &pkt, endpoint_t sender)
296296
size_t neededSize = sizeof(GameData) + (PlayerNameLength * MAX_PLRS);
297297
if (pkt.Info().size() < neededSize)
298298
return;
299-
const GameData *gameData = (const GameData *)pkt.Info().data();
300-
if (gameData->size != sizeof(GameData))
299+
GameData gameData;
300+
std::memcpy(&gameData, pkt.Info().data(), sizeof(GameData));
301+
gameData.swapLE();
302+
if (gameData.size != sizeof(GameData))
301303
return;
302304
std::vector<std::string> playerNames;
303305
for (size_t i = 0; i < Players.size(); i++) {
@@ -316,7 +318,7 @@ void base_protocol<P>::recv_decrypted(packet &pkt, endpoint_t sender)
316318
size_t gameNameSize = pkt.Info().size() - neededSize;
317319
gameName.resize(gameNameSize);
318320
std::memcpy(&gameName[0], pkt.Info().data() + neededSize, gameNameSize);
319-
game_list[gameName] = std::make_tuple(*gameData, playerNames, sender);
321+
game_list[gameName] = std::make_tuple(gameData, playerNames, sender);
320322
return;
321323
}
322324
recv_ingame(pkt, sender);

Source/dvlnet/frame_queue.cpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "appfat.h"
66
#include "dvlnet/packet.h"
77
#include "utils/attributes.h"
8+
#include "utils/endian.hpp"
89

910
namespace devilution {
1011
namespace net {
@@ -56,7 +57,7 @@ bool frame_queue::PacketReady()
5657
if (Size() < sizeof(framesize_t))
5758
return false;
5859
auto szbuf = Read(sizeof(framesize_t));
59-
std::memcpy(&nextsize, &szbuf[0], sizeof(framesize_t));
60+
nextsize = LoadLE32(szbuf.data());
6061
if (nextsize == 0)
6162
FRAME_QUEUE_ERROR;
6263
}
@@ -77,8 +78,11 @@ buffer_t frame_queue::MakeFrame(buffer_t packetbuf)
7778
buffer_t ret;
7879
if (packetbuf.size() > max_frame_size)
7980
ABORT();
80-
framesize_t size = packetbuf.size();
81-
ret.insert(ret.end(), packet_out::begin(size), packet_out::end(size));
81+
const framesize_t size = packetbuf.size();
82+
static_assert(sizeof(size) == 4, "framesize_t is not 4 bytes");
83+
unsigned char sizeBuf[4];
84+
WriteLE32(sizeBuf, size);
85+
ret.insert(ret.end(), sizeBuf, sizeBuf + 4);
8286
ret.insert(ret.end(), packetbuf.begin(), packetbuf.end());
8387
return ret;
8488
}

Source/dvlnet/packet.h

+26-21
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <cstring>
66
#include <memory>
77
#include <string>
8+
#include <type_traits>
89

910
#ifdef PACKET_ENCRYPTION
1011
#include <sodium.h>
@@ -40,7 +41,7 @@ typedef uint8_t plr_t;
4041
typedef uint8_t seq_t;
4142
typedef uint32_t cookie_t;
4243
typedef uint32_t timestamp_t;
43-
typedef int leaveinfo_t; // also change later
44+
typedef uint32_t leaveinfo_t;
4445
#ifdef PACKET_ENCRYPTION
4546
typedef std::array<unsigned char, crypto_secretbox_KEYBYTES> key_t;
4647
#else
@@ -140,11 +141,7 @@ class packet_out : public packet_proc<packet_out> {
140141

141142
void process_element(buffer_t &x);
142143
template <class T>
143-
void process_element(T &x);
144-
template <class T>
145-
static const unsigned char *begin(const T &x);
146-
template <class T>
147-
static const unsigned char *end(const T &x);
144+
void process_element(const T &x);
148145
static cookie_t GenerateCookie();
149146
void Encrypt();
150147
};
@@ -202,13 +199,21 @@ inline void packet_in::process_element(buffer_t &x)
202199
template <class T>
203200
void packet_in::process_element(T &x)
204201
{
202+
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "Unsupported T");
203+
static_assert(sizeof(T) == 4 || sizeof(T) == 2 || sizeof(T) == 1, "Unsupported T");
205204
if (decrypted_buffer.size() < sizeof(T))
206205
#if DVL_EXCEPTIONS
207206
throw packet_exception();
208207
#else
209208
app_fatal("invalid packet");
210209
#endif
211-
std::memcpy(&x, decrypted_buffer.data(), sizeof(T));
210+
if (sizeof(T) == 4) {
211+
x = static_cast<T>(LoadLE32(decrypted_buffer.data()));
212+
} else if (sizeof(T) == 2) {
213+
x = static_cast<T>(LoadLE16(decrypted_buffer.data()));
214+
} else if (sizeof(T) == 1) {
215+
std::memcpy(&x, decrypted_buffer.data(), sizeof(T));
216+
}
212217
decrypted_buffer.erase(decrypted_buffer.begin(),
213218
decrypted_buffer.begin() + sizeof(T));
214219
}
@@ -358,21 +363,21 @@ inline void packet_out::process_element(buffer_t &x)
358363
}
359364

360365
template <class T>
361-
void packet_out::process_element(T &x)
366+
void packet_out::process_element(const T &x)
362367
{
363-
decrypted_buffer.insert(decrypted_buffer.end(), begin(x), end(x));
364-
}
365-
366-
template <class T>
367-
const unsigned char *packet_out::begin(const T &x)
368-
{
369-
return reinterpret_cast<const unsigned char *>(&x);
370-
}
371-
372-
template <class T>
373-
const unsigned char *packet_out::end(const T &x)
374-
{
375-
return reinterpret_cast<const unsigned char *>(&x) + sizeof(T);
368+
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "Unsupported T");
369+
static_assert(sizeof(T) == 4 || sizeof(T) == 2 || sizeof(T) == 1, "Unsupported T");
370+
if (sizeof(T) == 4) {
371+
unsigned char buf[4];
372+
WriteLE32(buf, x);
373+
decrypted_buffer.insert(decrypted_buffer.end(), buf, buf + 4);
374+
} else if (sizeof(T) == 2) {
375+
unsigned char buf[2];
376+
WriteLE16(buf, x);
377+
decrypted_buffer.insert(decrypted_buffer.end(), buf, buf + 2);
378+
} else if (sizeof(T) == 1) {
379+
decrypted_buffer.push_back(static_cast<unsigned char>(x));
380+
}
376381
}
377382

378383
class packet_factory {

Source/dvlnet/tcp_server.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ void tcp_server::DropConnection(const scc &con)
214214
{
215215
if (con->plr != PLR_BROADCAST) {
216216
auto pkt = pktfty.make_packet<PT_DISCONNECT>(PLR_MASTER, PLR_BROADCAST,
217-
con->plr, LEAVE_DROP);
217+
con->plr, static_cast<leaveinfo_t>(LEAVE_DROP));
218218
connections[con->plr] = nullptr;
219219
SendPacket(*pkt);
220220
// TODO: investigate if it is really ok for the server to

Source/multi.cpp

+40-20
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
#include <cstdint>
8+
#include <cstring>
89
#include <ctime>
910

1011
#include <SDL.h>
@@ -46,7 +47,7 @@ bool sgbSendDeltaTbl[MAX_PLRS];
4647
GameData sgGameInitInfo;
4748
bool gbSelectProvider;
4849
int sglTimeoutStart;
49-
int sgdwPlayerLeftReasonTbl[MAX_PLRS];
50+
uint32_t sgdwPlayerLeftReasonTbl[MAX_PLRS];
5051
TBuffer lowPriorityBuffer;
5152
uint32_t sgdwGameLoops;
5253
/**
@@ -74,6 +75,13 @@ const event_type EventTypes[3] = {
7475
EVENT_TYPE_PLAYER_MESSAGE
7576
};
7677

78+
void GameData::swapLE()
79+
{
80+
size = SDL_SwapLE32(size);
81+
dwSeed = SDL_SwapLE32(dwSeed);
82+
programid = SDL_SwapLE32(programid);
83+
}
84+
7785
namespace {
7886

7987
constexpr uint16_t HeaderCheckVal =
@@ -376,34 +384,44 @@ void SetupLocalPositions()
376384

377385
void HandleEvents(_SNETEVENT *pEvt)
378386
{
387+
const uint32_t playerId = pEvt->playerid;
379388
switch (pEvt->eventid) {
380389
case EVENT_TYPE_PLAYER_CREATE_GAME: {
381-
auto *gameData = (GameData *)pEvt->data;
382-
if (gameData->size != sizeof(GameData))
383-
app_fatal(StrCat("Invalid size of game data: ", gameData->size));
384-
sgGameInitInfo = *gameData;
385-
sgbPlayerTurnBitTbl[pEvt->playerid] = true;
386-
break;
387-
}
390+
GameData gameData;
391+
if (pEvt->databytes < sizeof(GameData))
392+
app_fatal(StrCat("Invalid packet size (<sizeof(GameData)): ", pEvt->databytes));
393+
std::memcpy(&gameData, pEvt->data, sizeof(gameData));
394+
gameData.swapLE();
395+
if (gameData.size != sizeof(GameData))
396+
app_fatal(StrCat("Invalid size of game data: ", gameData.size));
397+
sgGameInitInfo = gameData;
398+
sgbPlayerTurnBitTbl[playerId] = true;
399+
} break;
388400
case EVENT_TYPE_PLAYER_LEAVE_GAME: {
389-
sgbPlayerLeftGameTbl[pEvt->playerid] = true;
390-
sgbPlayerTurnBitTbl[pEvt->playerid] = false;
401+
sgbPlayerLeftGameTbl[playerId] = true;
402+
sgbPlayerTurnBitTbl[playerId] = false;
391403

392-
int leftReason = 0;
393-
if (pEvt->data != nullptr && pEvt->databytes >= sizeof(leftReason))
394-
leftReason = *(int *)pEvt->data;
395-
sgdwPlayerLeftReasonTbl[pEvt->playerid] = leftReason;
404+
int32_t leftReason = 0;
405+
if (pEvt->data != nullptr && pEvt->databytes >= sizeof(leftReason)) {
406+
std::memcpy(&leftReason, pEvt->data, sizeof(leftReason));
407+
leftReason = SDL_SwapLE32(leftReason);
408+
}
409+
sgdwPlayerLeftReasonTbl[playerId] = leftReason;
396410
if (leftReason == LEAVE_ENDING)
397411
gbSomebodyWonGameKludge = true;
398412

399-
sgbSendDeltaTbl[pEvt->playerid] = false;
413+
sgbSendDeltaTbl[playerId] = false;
400414

401-
if (gbDeltaSender == pEvt->playerid)
415+
if (gbDeltaSender == playerId)
402416
gbDeltaSender = MAX_PLRS;
403417
} break;
404-
case EVENT_TYPE_PLAYER_MESSAGE:
405-
EventPlrMsg((char *)pEvt->data);
406-
break;
418+
case EVENT_TYPE_PLAYER_MESSAGE: {
419+
string_view data(static_cast<const char *>(pEvt->data), pEvt->databytes);
420+
if (const size_t nullPos = data.find('\0'); nullPos != string_view::npos) {
421+
data.remove_suffix(data.size() - nullPos);
422+
}
423+
EventPlrMsg(data);
424+
} break;
407425
}
408426
}
409427

@@ -432,7 +450,9 @@ bool InitSingle(GameData *gameData)
432450
}
433451

434452
int unused = 0;
435-
if (!SNetCreateGame("local", "local", (char *)&sgGameInitInfo, sizeof(sgGameInitInfo), &unused)) {
453+
GameData gameInitInfo = sgGameInitInfo;
454+
gameInitInfo.swapLE();
455+
if (!SNetCreateGame("local", "local", reinterpret_cast<char *>(&gameInitInfo), sizeof(gameInitInfo), &unused)) {
436456
app_fatal(StrCat("SNetCreateGame1:\n", SDL_GetError()));
437457
}
438458

Source/multi.h

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ struct GameData {
3232
uint8_t bCowQuest;
3333
uint8_t bFriendlyFire;
3434
uint8_t fullQuests;
35+
36+
void swapLE();
3537
};
3638

3739
/* @brief Contains info of running public game (for game list browsing) */

Source/storm/storm_net.hpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ struct _SNETCAPS {
3636
};
3737

3838
struct _SNETEVENT {
39-
uint32_t eventid;
40-
uint32_t playerid;
41-
void *data;
42-
uint32_t databytes;
39+
uint32_t eventid; // native-endian
40+
uint32_t playerid; // native-endian
41+
void *data; // little-endian
42+
uint32_t databytes; // native-endian
4343
};
4444

4545
#define PS_CONNECTED 0x10000

0 commit comments

Comments
 (0)