Skip to content

Commit 62539d8

Browse files
committed
Fix Instant Kick issue in MacOS LAN Lobby
- Synchronize m_localIP with the IP assigned by the host inside handleJoinAccept. This ensures MSG_GAME_OPTIONS parser correctly finds our local slot. - Fixed 32-to-64 bit packing issues by using mac_converters.cpp for LANMessage conversion over UDP. - Improved logging with explicit flushing.
1 parent ca8e1ed commit 62539d8

8 files changed

Lines changed: 342 additions & 59 deletions

File tree

Core/GameEngine/Include/GameNetwork/LANAPI.h

Lines changed: 41 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -275,62 +275,66 @@ static_assert(sizeof(LANMessage) <= MAX_LANAPI_PACKET_SIZE, "LANMessage struct c
275275
// We disable the assert for now, but cross-platform LAN play serialization must be fixed.
276276
static_assert(sizeof(LANMessage) <= MAX_LANAPI_PACKET_SIZE + 512, "LANMessage struct exceeds even macOS padded size limit");
277277

278+
#include <stdint.h>
278279
#pragma pack(push, 1)
279-
struct LANMessageWire
280-
{
281-
UnsignedInt messageType;
282-
283-
uint16_t name[g_lanPlayerNameLength + 1];
284-
char userName[g_lanLoginNameLength + 1];
285-
char hostName[g_lanHostNameLength + 1];
286-
287-
union
288-
{
289-
struct { Int seconds; } StartTimer;
290-
struct { uint16_t gameName[g_lanGameNameLength + 1]; } GameToLeave;
280+
struct LANMessageWire {
281+
uint32_t messageType;
282+
uint16_t name[13];
283+
char userName[2];
284+
char hostName[2];
285+
286+
union {
287+
struct {
288+
int32_t seconds;
289+
} StartTimer;
291290
struct {
292-
uint16_t gameName[g_lanGameNameLength + 1];
293-
Bool inProgress;
291+
uint16_t gameName[17];
292+
} GameToLeave;
293+
struct {
294+
uint16_t gameName[17];
295+
uint8_t inProgress;
294296
char options[m_lanMaxOptionsLength + 1];
295-
Bool isDirectConnect;
297+
uint8_t isDirectConnect;
296298
} GameInfo;
297299
struct {
298-
UnsignedInt ip;
299-
uint16_t playerName[g_lanPlayerNameLength + 1];
300+
uint32_t ip;
301+
uint16_t playerName[13];
300302
} PlayerInfo;
301303
struct {
302-
UnsignedInt gameIP;
303-
UnsignedInt exeCRC;
304-
UnsignedInt iniCRC;
304+
uint32_t gameIP;
305+
uint32_t exeCRC;
306+
uint32_t iniCRC;
305307
char serial[g_maxSerialLength];
306308
} GameToJoin;
307309
struct {
308-
uint16_t gameName[g_lanGameNameLength + 1];
309-
UnsignedInt gameIP;
310-
UnsignedInt playerIP;
311-
Int slotPosition;
310+
uint16_t gameName[17];
311+
uint32_t gameIP;
312+
uint32_t playerIP;
313+
int32_t slotPosition;
312314
} GameJoined;
313315
struct {
314-
uint16_t gameName[g_lanGameNameLength + 1];
315-
UnsignedInt gameIP;
316-
UnsignedInt playerIP;
317-
LANAPIInterface::ReturnType reason;
316+
uint16_t gameName[17];
317+
uint32_t gameIP;
318+
uint32_t playerIP;
319+
int32_t reason;
318320
} GameNotJoined;
319321
struct {
320-
uint16_t gameName[g_lanGameNameLength + 1];
321-
Bool isAccepted;
322+
uint16_t gameName[17];
323+
uint8_t isAccepted;
322324
} Accept;
323325
struct {
324-
uint16_t gameName[g_lanGameNameLength + 1];
325-
UnsignedInt mapCRC;
326-
Bool hasMap;
326+
uint16_t gameName[17];
327+
uint32_t mapCRC;
328+
uint8_t hasMap;
327329
} MapStatus;
328330
struct {
329-
uint16_t gameName[g_lanGameNameLength + 1];
330-
LANAPIInterface::ChatType chatType;
331-
uint16_t message[g_lanMaxChatLength + 1];
331+
uint16_t gameName[17];
332+
int32_t chatType;
333+
uint16_t message[101];
332334
} Chat;
333-
struct { char options[m_lanMaxOptionsLength+1]; } GameOptions;
335+
struct {
336+
char options[m_lanMaxOptionsLength+1];
337+
} GameOptions;
334338
};
335339
};
336340
#pragma pack(pop)
@@ -340,7 +344,6 @@ void ConvertLANMessageToWire(const LANMessage* msg, LANMessageWire* wire);
340344

341345
#endif
342346

343-
344347
/**
345348
* The LANAPI class is used to instantiate a singleton which
346349
* implements the interface to all LAN broadcast communications.

Core/GameEngine/Source/GameNetwork/IPEnumeration.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <arpa/inet.h>
3636
#include <netdb.h>
3737
#include <errno.h>
38+
#include <ifaddrs.h>
3839
#define WSAGetLastError() (errno)
3940
#define closesocket close
4041
#define HOSTENT struct hostent
@@ -89,6 +90,32 @@ EnumeratedIP * IPEnumeration::getAddresses()
8990
m_isWinsockInitialized = true;
9091
}
9192

93+
#ifdef __APPLE__
94+
struct ifaddrs *interfaces = nullptr;
95+
if (getifaddrs(&interfaces) == 0) {
96+
for (struct ifaddrs *temp = interfaces; temp != nullptr; temp = temp->ifa_next) {
97+
if (temp->ifa_addr != nullptr && temp->ifa_addr->sa_family == AF_INET) {
98+
struct sockaddr_in *addr = (struct sockaddr_in *)temp->ifa_addr;
99+
UnsignedInt ip = ntohl(addr->sin_addr.s_addr);
100+
// Skip loopback (127.x.x.x) unless we have nothing else,
101+
// but typically we want the actual LAN address.
102+
if ((ip & 0xFF000000) != 0x7F000000) {
103+
addNewIP(
104+
(UnsignedByte)(ip >> 24),
105+
(UnsignedByte)(ip >> 16),
106+
(UnsignedByte)(ip >> 8),
107+
(UnsignedByte)(ip));
108+
}
109+
}
110+
}
111+
freeifaddrs(interfaces);
112+
}
113+
114+
// Fallback if no non-loopback IPs found
115+
if (!m_IPlist) {
116+
addNewIP(127, 0, 0, 1);
117+
}
118+
#else
92119
// get the local machine's host name
93120
char hostname[256];
94121
if (gethostname(hostname, sizeof(hostname)))
@@ -135,6 +162,7 @@ EnumeratedIP * IPEnumeration::getAddresses()
135162
(UnsignedByte)entry[2],
136163
(UnsignedByte)entry[3]);
137164
}
165+
#endif
138166

139167
return m_IPlist;
140168
}

Core/GameEngine/Source/GameNetwork/LANAPI.cpp

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,10 @@ void LANAPI::sendMessage(LANMessage* msg, UnsignedInt ip /* = 0 */)
185185
LANMessageWire wireMsg;
186186
ConvertLANMessageToWire(msg, &wireMsg);
187187
unsigned char* payload = (unsigned char*)&wireMsg;
188-
size_t payloadSize = sizeof(LANMessageWire);
188+
int payloadSize = (int)sizeof(LANMessageWire);
189189
#else
190190
unsigned char* payload = (unsigned char*)msg;
191-
size_t payloadSize = sizeof(LANMessage);
191+
int payloadSize = (int)sizeof(LANMessage);
192192
#endif
193193

194194
if (ip != 0)
@@ -360,17 +360,26 @@ void LANAPI::update()
360360
UnsignedInt senderIP = m_transport->m_inBuffer[i].addr;
361361
if (senderIP == m_localIP)
362362
{
363+
#ifdef __APPLE__
364+
printf("MAC_LANAPI: Dropping packet from senderIP %08X because it matches m_localIP!\n", senderIP);
365+
fflush(stdout);
366+
#endif
363367
m_transport->m_inBuffer[i].length = 0;
364368
continue;
365369
}
366370

367-
#ifdef __APPLE__
368371
LANMessage msgBuffer;
372+
#ifdef __APPLE__
369373
LANMessageWire* wireMsg = (LANMessageWire*)(m_transport->m_inBuffer[i].data);
370374
ConvertWireToLANMessage(wireMsg, &msgBuffer);
371-
LANMessage* msg = &msgBuffer;
372375
#else
373-
LANMessage* msg = (LANMessage*)(m_transport->m_inBuffer[i].data);
376+
memcpy(&msgBuffer, m_transport->m_inBuffer[i].data, sizeof(LANMessage));
377+
#endif
378+
LANMessage* msg = &msgBuffer;
379+
380+
#ifdef __APPLE__
381+
printf("MAC_LANAPI: Processing messageType %d from %08X\n", msg->messageType, senderIP);
382+
fflush(stdout);
374383
#endif
375384

376385
//DEBUG_LOG(("LAN message type %s from %ls (%s@%s)", GetMessageTypeString(msg->messageType).str(),
@@ -1347,9 +1356,9 @@ void ConvertWireToLANMessage(const LANMessageWire* wire, LANMessage* msg) {
13471356
break;
13481357
case LANMessage::MSG_GAME_ANNOUNCE:
13491358
CopyWireToWide(msg->GameInfo.gameName, wire->GameInfo.gameName, ARRAY_SIZE(wire->GameInfo.gameName));
1350-
msg->GameInfo.inProgress = wire->GameInfo.inProgress;
1359+
msg->GameInfo.inProgress = (Bool)wire->GameInfo.inProgress;
13511360
memcpy(msg->GameInfo.options, wire->GameInfo.options, sizeof(wire->GameInfo.options));
1352-
msg->GameInfo.isDirectConnect = wire->GameInfo.isDirectConnect;
1361+
msg->GameInfo.isDirectConnect = (Bool)wire->GameInfo.isDirectConnect;
13531362
break;
13541363
case LANMessage::MSG_REQUEST_GAME_INFO:
13551364
msg->PlayerInfo.ip = wire->PlayerInfo.ip;
@@ -1371,20 +1380,20 @@ void ConvertWireToLANMessage(const LANMessageWire* wire, LANMessage* msg) {
13711380
CopyWireToWide(msg->GameNotJoined.gameName, wire->GameNotJoined.gameName, ARRAY_SIZE(wire->GameNotJoined.gameName));
13721381
msg->GameNotJoined.gameIP = wire->GameNotJoined.gameIP;
13731382
msg->GameNotJoined.playerIP = wire->GameNotJoined.playerIP;
1374-
msg->GameNotJoined.reason = wire->GameNotJoined.reason;
1383+
msg->GameNotJoined.reason = (LANAPIInterface::ReturnType)wire->GameNotJoined.reason;
13751384
break;
13761385
case LANMessage::MSG_SET_ACCEPT:
13771386
CopyWireToWide(msg->Accept.gameName, wire->Accept.gameName, ARRAY_SIZE(wire->Accept.gameName));
1378-
msg->Accept.isAccepted = wire->Accept.isAccepted;
1387+
msg->Accept.isAccepted = (Bool)wire->Accept.isAccepted;
13791388
break;
13801389
case LANMessage::MSG_MAP_AVAILABILITY:
13811390
CopyWireToWide(msg->MapStatus.gameName, wire->MapStatus.gameName, ARRAY_SIZE(wire->MapStatus.gameName));
13821391
msg->MapStatus.mapCRC = wire->MapStatus.mapCRC;
1383-
msg->MapStatus.hasMap = wire->MapStatus.hasMap;
1392+
msg->MapStatus.hasMap = (Bool)wire->MapStatus.hasMap;
13841393
break;
13851394
case LANMessage::MSG_CHAT:
13861395
CopyWireToWide(msg->Chat.gameName, wire->Chat.gameName, ARRAY_SIZE(wire->Chat.gameName));
1387-
msg->Chat.chatType = wire->Chat.chatType;
1396+
msg->Chat.chatType = (LANAPIInterface::ChatType)wire->Chat.chatType;
13881397
CopyWireToWide(msg->Chat.message, wire->Chat.message, ARRAY_SIZE(wire->Chat.message));
13891398
break;
13901399
case LANMessage::MSG_GAME_OPTIONS:
@@ -1395,7 +1404,7 @@ void ConvertWireToLANMessage(const LANMessageWire* wire, LANMessage* msg) {
13951404

13961405
void ConvertLANMessageToWire(const LANMessage* msg, LANMessageWire* wire) {
13971406
memset(wire, 0, sizeof(LANMessageWire));
1398-
wire->messageType = msg->messageType;
1407+
wire->messageType = (uint32_t)msg->messageType;
13991408
CopyWideToWire(wire->name, msg->name, ARRAY_SIZE(msg->name));
14001409
memcpy(wire->userName, msg->userName, sizeof(msg->userName));
14011410
memcpy(wire->hostName, msg->hostName, sizeof(msg->hostName));
@@ -1409,9 +1418,9 @@ void ConvertLANMessageToWire(const LANMessage* msg, LANMessageWire* wire) {
14091418
break;
14101419
case LANMessage::MSG_GAME_ANNOUNCE:
14111420
CopyWideToWire(wire->GameInfo.gameName, msg->GameInfo.gameName, ARRAY_SIZE(msg->GameInfo.gameName));
1412-
wire->GameInfo.inProgress = msg->GameInfo.inProgress;
1421+
wire->GameInfo.inProgress = msg->GameInfo.inProgress ? 1 : 0;
14131422
memcpy(wire->GameInfo.options, msg->GameInfo.options, sizeof(msg->GameInfo.options));
1414-
wire->GameInfo.isDirectConnect = msg->GameInfo.isDirectConnect;
1423+
wire->GameInfo.isDirectConnect = msg->GameInfo.isDirectConnect ? 1 : 0;
14151424
break;
14161425
case LANMessage::MSG_REQUEST_GAME_INFO:
14171426
wire->PlayerInfo.ip = msg->PlayerInfo.ip;
@@ -1433,20 +1442,20 @@ void ConvertLANMessageToWire(const LANMessage* msg, LANMessageWire* wire) {
14331442
CopyWideToWire(wire->GameNotJoined.gameName, msg->GameNotJoined.gameName, ARRAY_SIZE(msg->GameNotJoined.gameName));
14341443
wire->GameNotJoined.gameIP = msg->GameNotJoined.gameIP;
14351444
wire->GameNotJoined.playerIP = msg->GameNotJoined.playerIP;
1436-
wire->GameNotJoined.reason = msg->GameNotJoined.reason;
1445+
wire->GameNotJoined.reason = (int32_t)msg->GameNotJoined.reason;
14371446
break;
14381447
case LANMessage::MSG_SET_ACCEPT:
14391448
CopyWideToWire(wire->Accept.gameName, msg->Accept.gameName, ARRAY_SIZE(msg->Accept.gameName));
1440-
wire->Accept.isAccepted = msg->Accept.isAccepted;
1449+
wire->Accept.isAccepted = msg->Accept.isAccepted ? 1 : 0;
14411450
break;
14421451
case LANMessage::MSG_MAP_AVAILABILITY:
14431452
CopyWideToWire(wire->MapStatus.gameName, msg->MapStatus.gameName, ARRAY_SIZE(msg->MapStatus.gameName));
14441453
wire->MapStatus.mapCRC = msg->MapStatus.mapCRC;
1445-
wire->MapStatus.hasMap = msg->MapStatus.hasMap;
1454+
wire->MapStatus.hasMap = msg->MapStatus.hasMap ? 1 : 0;
14461455
break;
14471456
case LANMessage::MSG_CHAT:
14481457
CopyWideToWire(wire->Chat.gameName, msg->Chat.gameName, ARRAY_SIZE(msg->Chat.gameName));
1449-
wire->Chat.chatType = msg->Chat.chatType;
1458+
wire->Chat.chatType = (int32_t)msg->Chat.chatType;
14501459
CopyWideToWire(wire->Chat.message, msg->Chat.message, ARRAY_SIZE(msg->Chat.message));
14511460
break;
14521461
case LANMessage::MSG_GAME_OPTIONS:
@@ -1455,4 +1464,3 @@ void ConvertLANMessageToWire(const LANMessage* msg, LANMessageWire* wire) {
14551464
}
14561465
}
14571466
#endif
1458-

Core/GameEngine/Source/GameNetwork/LANAPICallbacks.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,16 @@ void LANAPI::OnGameOptions( UnsignedInt playerIP, Int playerSlot, AsciiString op
284284
updateGameOptions();
285285
}
286286
Bool booted = true;
287+
#ifdef __APPLE__
288+
printf("MAC_LANAPI: OnGameOptions: m_localIP=0x%08X, options string: %s\n", m_localIP, options.str());
289+
fflush(stdout);
290+
#endif
287291
for(Int player = 1; player< MAX_SLOTS; player++)
288292
{
293+
#ifdef __APPLE__
294+
printf("MAC_LANAPI: OnGameOptions check: slot %d IP=0x%08X\n", player, m_currentGame->getIP(player));
295+
fflush(stdout);
296+
#endif
289297
if(m_currentGame->getIP(player) == m_localIP)
290298
{
291299
booted = false;
@@ -294,6 +302,10 @@ void LANAPI::OnGameOptions( UnsignedInt playerIP, Int playerSlot, AsciiString op
294302
}
295303
if(booted)
296304
{
305+
#ifdef __APPLE__
306+
printf("MAC_LANAPI: OnGameOptions: Booted! Could not find m_localIP in the parsed game options.\n");
307+
fflush(stdout);
308+
#endif
297309
// restore the options with us in so we can save prefs
298310
ParseGameOptionsString(m_currentGame, oldOptions);
299311
OnPlayerLeave(m_name);

0 commit comments

Comments
 (0)