mirror of
https://github.com/diasurgical/DevilutionX.git
synced 2026-10-12 02:13:06 +00:00
Big-endian networking fixes
This commit is contained in:
committed by
Anders Jenbo
parent
fb625d826f
commit
72d8a56d1b
@@ -660,7 +660,9 @@ void selgame_Password_Select(int /*value*/)
|
||||
m_game_data->bTheoQuest = *sgOptions.Gameplay.theoQuest ? 1 : 0;
|
||||
m_game_data->bCowQuest = *sgOptions.Gameplay.cowQuest ? 1 : 0;
|
||||
|
||||
if (SNetCreateGame(nullptr, gamePassword, (char *)m_game_data, sizeof(*m_game_data), gdwPlayerId)) {
|
||||
GameData gameInitInfo = *m_game_data;
|
||||
gameInitInfo.swapLE();
|
||||
if (SNetCreateGame(nullptr, gamePassword, reinterpret_cast<char *>(&gameInitInfo), sizeof(gameInitInfo), gdwPlayerId)) {
|
||||
UiInitList_clear();
|
||||
selgame_endMenu = true;
|
||||
} else {
|
||||
|
||||
@@ -401,7 +401,7 @@ bool base::SNetRegisterEventHandler(event_type evtype, SEVTHANDLER func)
|
||||
bool base::SNetLeaveGame(int type)
|
||||
{
|
||||
auto pkt = pktfty->make_packet<PT_DISCONNECT>(plr_self, PLR_BROADCAST,
|
||||
plr_self, type);
|
||||
plr_self, static_cast<leaveinfo_t>(type));
|
||||
send(*pkt);
|
||||
plr_self = PLR_BROADCAST;
|
||||
return true;
|
||||
@@ -411,8 +411,8 @@ bool base::SNetDropPlayer(int playerid, uint32_t flags)
|
||||
{
|
||||
auto pkt = pktfty->make_packet<PT_DISCONNECT>(plr_self,
|
||||
PLR_BROADCAST,
|
||||
(plr_t)playerid,
|
||||
(leaveinfo_t)flags);
|
||||
static_cast<plr_t>(playerid),
|
||||
static_cast<leaveinfo_t>(flags));
|
||||
send(*pkt);
|
||||
RecvLocal(*pkt);
|
||||
return true;
|
||||
|
||||
@@ -296,8 +296,10 @@ void base_protocol<P>::recv_decrypted(packet &pkt, endpoint_t sender)
|
||||
size_t neededSize = sizeof(GameData) + (PlayerNameLength * MAX_PLRS);
|
||||
if (pkt.Info().size() < neededSize)
|
||||
return;
|
||||
const GameData *gameData = (const GameData *)pkt.Info().data();
|
||||
if (gameData->size != sizeof(GameData))
|
||||
GameData gameData;
|
||||
std::memcpy(&gameData, pkt.Info().data(), sizeof(GameData));
|
||||
gameData.swapLE();
|
||||
if (gameData.size != sizeof(GameData))
|
||||
return;
|
||||
std::vector<std::string> playerNames;
|
||||
for (size_t i = 0; i < Players.size(); i++) {
|
||||
@@ -316,7 +318,7 @@ void base_protocol<P>::recv_decrypted(packet &pkt, endpoint_t sender)
|
||||
size_t gameNameSize = pkt.Info().size() - neededSize;
|
||||
gameName.resize(gameNameSize);
|
||||
std::memcpy(&gameName[0], pkt.Info().data() + neededSize, gameNameSize);
|
||||
game_list[gameName] = std::make_tuple(*gameData, playerNames, sender);
|
||||
game_list[gameName] = std::make_tuple(gameData, playerNames, sender);
|
||||
return;
|
||||
}
|
||||
recv_ingame(pkt, sender);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "appfat.h"
|
||||
#include "dvlnet/packet.h"
|
||||
#include "utils/attributes.h"
|
||||
#include "utils/endian.hpp"
|
||||
|
||||
namespace devilution {
|
||||
namespace net {
|
||||
@@ -56,7 +57,7 @@ bool frame_queue::PacketReady()
|
||||
if (Size() < sizeof(framesize_t))
|
||||
return false;
|
||||
auto szbuf = Read(sizeof(framesize_t));
|
||||
std::memcpy(&nextsize, &szbuf[0], sizeof(framesize_t));
|
||||
nextsize = LoadLE32(szbuf.data());
|
||||
if (nextsize == 0)
|
||||
FRAME_QUEUE_ERROR;
|
||||
}
|
||||
@@ -77,8 +78,11 @@ buffer_t frame_queue::MakeFrame(buffer_t packetbuf)
|
||||
buffer_t ret;
|
||||
if (packetbuf.size() > max_frame_size)
|
||||
ABORT();
|
||||
framesize_t size = packetbuf.size();
|
||||
ret.insert(ret.end(), packet_out::begin(size), packet_out::end(size));
|
||||
const framesize_t size = packetbuf.size();
|
||||
static_assert(sizeof(size) == 4, "framesize_t is not 4 bytes");
|
||||
unsigned char sizeBuf[4];
|
||||
WriteLE32(sizeBuf, size);
|
||||
ret.insert(ret.end(), sizeBuf, sizeBuf + 4);
|
||||
ret.insert(ret.end(), packetbuf.begin(), packetbuf.end());
|
||||
return ret;
|
||||
}
|
||||
|
||||
+26
-21
@@ -5,6 +5,7 @@
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef PACKET_ENCRYPTION
|
||||
#include <sodium.h>
|
||||
@@ -40,7 +41,7 @@ typedef uint8_t plr_t;
|
||||
typedef uint8_t seq_t;
|
||||
typedef uint32_t cookie_t;
|
||||
typedef uint32_t timestamp_t;
|
||||
typedef int leaveinfo_t; // also change later
|
||||
typedef uint32_t leaveinfo_t;
|
||||
#ifdef PACKET_ENCRYPTION
|
||||
typedef std::array<unsigned char, crypto_secretbox_KEYBYTES> key_t;
|
||||
#else
|
||||
@@ -140,11 +141,7 @@ public:
|
||||
|
||||
void process_element(buffer_t &x);
|
||||
template <class T>
|
||||
void process_element(T &x);
|
||||
template <class T>
|
||||
static const unsigned char *begin(const T &x);
|
||||
template <class T>
|
||||
static const unsigned char *end(const T &x);
|
||||
void process_element(const T &x);
|
||||
static cookie_t GenerateCookie();
|
||||
void Encrypt();
|
||||
};
|
||||
@@ -202,13 +199,21 @@ inline void packet_in::process_element(buffer_t &x)
|
||||
template <class T>
|
||||
void packet_in::process_element(T &x)
|
||||
{
|
||||
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "Unsupported T");
|
||||
static_assert(sizeof(T) == 4 || sizeof(T) == 2 || sizeof(T) == 1, "Unsupported T");
|
||||
if (decrypted_buffer.size() < sizeof(T))
|
||||
#if DVL_EXCEPTIONS
|
||||
throw packet_exception();
|
||||
#else
|
||||
app_fatal("invalid packet");
|
||||
#endif
|
||||
std::memcpy(&x, decrypted_buffer.data(), sizeof(T));
|
||||
if (sizeof(T) == 4) {
|
||||
x = static_cast<T>(LoadLE32(decrypted_buffer.data()));
|
||||
} else if (sizeof(T) == 2) {
|
||||
x = static_cast<T>(LoadLE16(decrypted_buffer.data()));
|
||||
} else if (sizeof(T) == 1) {
|
||||
std::memcpy(&x, decrypted_buffer.data(), sizeof(T));
|
||||
}
|
||||
decrypted_buffer.erase(decrypted_buffer.begin(),
|
||||
decrypted_buffer.begin() + sizeof(T));
|
||||
}
|
||||
@@ -358,21 +363,21 @@ inline void packet_out::process_element(buffer_t &x)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void packet_out::process_element(T &x)
|
||||
void packet_out::process_element(const T &x)
|
||||
{
|
||||
decrypted_buffer.insert(decrypted_buffer.end(), begin(x), end(x));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const unsigned char *packet_out::begin(const T &x)
|
||||
{
|
||||
return reinterpret_cast<const unsigned char *>(&x);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const unsigned char *packet_out::end(const T &x)
|
||||
{
|
||||
return reinterpret_cast<const unsigned char *>(&x) + sizeof(T);
|
||||
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "Unsupported T");
|
||||
static_assert(sizeof(T) == 4 || sizeof(T) == 2 || sizeof(T) == 1, "Unsupported T");
|
||||
if (sizeof(T) == 4) {
|
||||
unsigned char buf[4];
|
||||
WriteLE32(buf, x);
|
||||
decrypted_buffer.insert(decrypted_buffer.end(), buf, buf + 4);
|
||||
} else if (sizeof(T) == 2) {
|
||||
unsigned char buf[2];
|
||||
WriteLE16(buf, x);
|
||||
decrypted_buffer.insert(decrypted_buffer.end(), buf, buf + 2);
|
||||
} else if (sizeof(T) == 1) {
|
||||
decrypted_buffer.push_back(static_cast<unsigned char>(x));
|
||||
}
|
||||
}
|
||||
|
||||
class packet_factory {
|
||||
|
||||
@@ -214,7 +214,7 @@ void tcp_server::DropConnection(const scc &con)
|
||||
{
|
||||
if (con->plr != PLR_BROADCAST) {
|
||||
auto pkt = pktfty.make_packet<PT_DISCONNECT>(PLR_MASTER, PLR_BROADCAST,
|
||||
con->plr, LEAVE_DROP);
|
||||
con->plr, static_cast<leaveinfo_t>(LEAVE_DROP));
|
||||
connections[con->plr] = nullptr;
|
||||
SendPacket(*pkt);
|
||||
// TODO: investigate if it is really ok for the server to
|
||||
|
||||
+40
-20
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
#include <SDL.h>
|
||||
@@ -46,7 +47,7 @@ bool sgbSendDeltaTbl[MAX_PLRS];
|
||||
GameData sgGameInitInfo;
|
||||
bool gbSelectProvider;
|
||||
int sglTimeoutStart;
|
||||
int sgdwPlayerLeftReasonTbl[MAX_PLRS];
|
||||
uint32_t sgdwPlayerLeftReasonTbl[MAX_PLRS];
|
||||
TBuffer lowPriorityBuffer;
|
||||
uint32_t sgdwGameLoops;
|
||||
/**
|
||||
@@ -74,6 +75,13 @@ const event_type EventTypes[3] = {
|
||||
EVENT_TYPE_PLAYER_MESSAGE
|
||||
};
|
||||
|
||||
void GameData::swapLE()
|
||||
{
|
||||
size = SDL_SwapLE32(size);
|
||||
dwSeed = SDL_SwapLE32(dwSeed);
|
||||
programid = SDL_SwapLE32(programid);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint16_t HeaderCheckVal =
|
||||
@@ -376,34 +384,44 @@ void SetupLocalPositions()
|
||||
|
||||
void HandleEvents(_SNETEVENT *pEvt)
|
||||
{
|
||||
const uint32_t playerId = pEvt->playerid;
|
||||
switch (pEvt->eventid) {
|
||||
case EVENT_TYPE_PLAYER_CREATE_GAME: {
|
||||
auto *gameData = (GameData *)pEvt->data;
|
||||
if (gameData->size != sizeof(GameData))
|
||||
app_fatal(StrCat("Invalid size of game data: ", gameData->size));
|
||||
sgGameInitInfo = *gameData;
|
||||
sgbPlayerTurnBitTbl[pEvt->playerid] = true;
|
||||
break;
|
||||
}
|
||||
GameData gameData;
|
||||
if (pEvt->databytes < sizeof(GameData))
|
||||
app_fatal(StrCat("Invalid packet size (<sizeof(GameData)): ", pEvt->databytes));
|
||||
std::memcpy(&gameData, pEvt->data, sizeof(gameData));
|
||||
gameData.swapLE();
|
||||
if (gameData.size != sizeof(GameData))
|
||||
app_fatal(StrCat("Invalid size of game data: ", gameData.size));
|
||||
sgGameInitInfo = gameData;
|
||||
sgbPlayerTurnBitTbl[playerId] = true;
|
||||
} break;
|
||||
case EVENT_TYPE_PLAYER_LEAVE_GAME: {
|
||||
sgbPlayerLeftGameTbl[pEvt->playerid] = true;
|
||||
sgbPlayerTurnBitTbl[pEvt->playerid] = false;
|
||||
sgbPlayerLeftGameTbl[playerId] = true;
|
||||
sgbPlayerTurnBitTbl[playerId] = false;
|
||||
|
||||
int leftReason = 0;
|
||||
if (pEvt->data != nullptr && pEvt->databytes >= sizeof(leftReason))
|
||||
leftReason = *(int *)pEvt->data;
|
||||
sgdwPlayerLeftReasonTbl[pEvt->playerid] = leftReason;
|
||||
int32_t leftReason = 0;
|
||||
if (pEvt->data != nullptr && pEvt->databytes >= sizeof(leftReason)) {
|
||||
std::memcpy(&leftReason, pEvt->data, sizeof(leftReason));
|
||||
leftReason = SDL_SwapLE32(leftReason);
|
||||
}
|
||||
sgdwPlayerLeftReasonTbl[playerId] = leftReason;
|
||||
if (leftReason == LEAVE_ENDING)
|
||||
gbSomebodyWonGameKludge = true;
|
||||
|
||||
sgbSendDeltaTbl[pEvt->playerid] = false;
|
||||
sgbSendDeltaTbl[playerId] = false;
|
||||
|
||||
if (gbDeltaSender == pEvt->playerid)
|
||||
if (gbDeltaSender == playerId)
|
||||
gbDeltaSender = MAX_PLRS;
|
||||
} break;
|
||||
case EVENT_TYPE_PLAYER_MESSAGE:
|
||||
EventPlrMsg((char *)pEvt->data);
|
||||
break;
|
||||
case EVENT_TYPE_PLAYER_MESSAGE: {
|
||||
string_view data(static_cast<const char *>(pEvt->data), pEvt->databytes);
|
||||
if (const size_t nullPos = data.find('\0'); nullPos != string_view::npos) {
|
||||
data.remove_suffix(data.size() - nullPos);
|
||||
}
|
||||
EventPlrMsg(data);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,7 +450,9 @@ bool InitSingle(GameData *gameData)
|
||||
}
|
||||
|
||||
int unused = 0;
|
||||
if (!SNetCreateGame("local", "local", (char *)&sgGameInitInfo, sizeof(sgGameInitInfo), &unused)) {
|
||||
GameData gameInitInfo = sgGameInitInfo;
|
||||
gameInitInfo.swapLE();
|
||||
if (!SNetCreateGame("local", "local", reinterpret_cast<char *>(&gameInitInfo), sizeof(gameInitInfo), &unused)) {
|
||||
app_fatal(StrCat("SNetCreateGame1:\n", SDL_GetError()));
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ struct GameData {
|
||||
uint8_t bCowQuest;
|
||||
uint8_t bFriendlyFire;
|
||||
uint8_t fullQuests;
|
||||
|
||||
void swapLE();
|
||||
};
|
||||
|
||||
/* @brief Contains info of running public game (for game list browsing) */
|
||||
|
||||
@@ -36,10 +36,10 @@ struct _SNETCAPS {
|
||||
};
|
||||
|
||||
struct _SNETEVENT {
|
||||
uint32_t eventid;
|
||||
uint32_t playerid;
|
||||
void *data;
|
||||
uint32_t databytes;
|
||||
uint32_t eventid; // native-endian
|
||||
uint32_t playerid; // native-endian
|
||||
void *data; // little-endian
|
||||
uint32_t databytes; // native-endian
|
||||
};
|
||||
|
||||
#define PS_CONNECTED 0x10000
|
||||
|
||||
Reference in New Issue
Block a user