aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/Windows64/Network
diff options
context:
space:
mode:
Diffstat (limited to 'Minecraft.Client/Windows64/Network')
-rw-r--r--Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp100
-rw-r--r--Minecraft.Client/Windows64/Network/WinsockNetLayer.h12
2 files changed, 95 insertions, 17 deletions
diff --git a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp
index ca1d62af..c76bc2fe 100644
--- a/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp
+++ b/Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp
@@ -8,6 +8,11 @@
#include "WinsockNetLayer.h"
#include "..\..\Common\Network\PlatformNetworkManagerStub.h"
#include "..\..\..\Minecraft.World\Socket.h"
+#include "..\..\..\Minecraft.World\DisconnectPacket.h"
+#include "..\..\Minecraft.h"
+#include "..\4JLibs\inc\4J_Profile.h"
+
+static bool RecvExact(SOCKET sock, BYTE* buf, int len);
SOCKET WinsockNetLayer::s_listenSocket = INVALID_SOCKET;
SOCKET WinsockNetLayer::s_hostConnectionSocket = INVALID_SOCKET;
@@ -21,7 +26,7 @@ bool WinsockNetLayer::s_initialized = false;
BYTE WinsockNetLayer::s_localSmallId = 0;
BYTE WinsockNetLayer::s_hostSmallId = 0;
-BYTE WinsockNetLayer::s_nextSmallId = 1;
+unsigned int WinsockNetLayer::s_nextSmallId = 1;
CRITICAL_SECTION WinsockNetLayer::s_sendLock;
CRITICAL_SECTION WinsockNetLayer::s_connectionsLock;
@@ -46,6 +51,8 @@ std::vector<BYTE> WinsockNetLayer::s_disconnectedSmallIds;
CRITICAL_SECTION WinsockNetLayer::s_freeSmallIdLock;
std::vector<BYTE> WinsockNetLayer::s_freeSmallIds;
+SOCKET WinsockNetLayer::s_smallIdToSocket[256];
+CRITICAL_SECTION WinsockNetLayer::s_smallIdToSocketLock;
bool g_Win64MultiplayerHost = false;
bool g_Win64MultiplayerJoin = false;
@@ -73,6 +80,9 @@ bool WinsockNetLayer::Initialize()
InitializeCriticalSection(&s_discoveryLock);
InitializeCriticalSection(&s_disconnectLock);
InitializeCriticalSection(&s_freeSmallIdLock);
+ InitializeCriticalSection(&s_smallIdToSocketLock);
+ for (int i = 0; i < 256; i++)
+ s_smallIdToSocket[i] = INVALID_SOCKET;
s_initialized = true;
@@ -137,6 +147,7 @@ void WinsockNetLayer::Shutdown()
s_disconnectedSmallIds.clear();
DeleteCriticalSection(&s_freeSmallIdLock);
s_freeSmallIds.clear();
+ DeleteCriticalSection(&s_smallIdToSocketLock);
WSACleanup();
s_initialized = false;
}
@@ -155,6 +166,10 @@ bool WinsockNetLayer::HostGame(int port, const char* bindIp)
EnterCriticalSection(&s_freeSmallIdLock);
s_freeSmallIds.clear();
LeaveCriticalSection(&s_freeSmallIdLock);
+ EnterCriticalSection(&s_smallIdToSocketLock);
+ for (int i = 0; i < 256; i++)
+ s_smallIdToSocket[i] = INVALID_SOCKET;
+ LeaveCriticalSection(&s_smallIdToSocketLock);
struct addrinfo hints = {};
struct addrinfo* result = NULL;
@@ -289,6 +304,27 @@ bool WinsockNetLayer::JoinGame(const char* ip, int port)
continue;
}
+ if (assignBuf[0] == WIN64_SMALLID_REJECT)
+ {
+ BYTE rejectBuf[5];
+ if (!RecvExact(s_hostConnectionSocket, rejectBuf, 5))
+ {
+ app.DebugPrintf("Failed to receive reject reason from host\n");
+ closesocket(s_hostConnectionSocket);
+ s_hostConnectionSocket = INVALID_SOCKET;
+ Sleep(200);
+ continue;
+ }
+ // rejectBuf[0] = packet id (255), rejectBuf[1..4] = 4-byte big-endian reason
+ int reason = ((rejectBuf[1] & 0xff) << 24) | ((rejectBuf[2] & 0xff) << 16) |
+ ((rejectBuf[3] & 0xff) << 8) | (rejectBuf[4] & 0xff);
+ Minecraft::GetInstance()->connectionDisconnected(ProfileManager.GetPrimaryPad(), (DisconnectPacket::eDisconnectReason)reason);
+ closesocket(s_hostConnectionSocket);
+ s_hostConnectionSocket = INVALID_SOCKET;
+ freeaddrinfo(result);
+ return false;
+ }
+
assignedSmallId = assignBuf[0];
connected = true;
break;
@@ -370,18 +406,31 @@ bool WinsockNetLayer::SendToSmallId(BYTE targetSmallId, const void* data, int da
SOCKET WinsockNetLayer::GetSocketForSmallId(BYTE smallId)
{
- EnterCriticalSection(&s_connectionsLock);
- for (size_t i = 0; i < s_connections.size(); i++)
- {
- if (s_connections[i].smallId == smallId && s_connections[i].active)
- {
- SOCKET sock = s_connections[i].tcpSocket;
- LeaveCriticalSection(&s_connectionsLock);
- return sock;
- }
- }
- LeaveCriticalSection(&s_connectionsLock);
- return INVALID_SOCKET;
+ EnterCriticalSection(&s_smallIdToSocketLock);
+ SOCKET sock = s_smallIdToSocket[smallId];
+ LeaveCriticalSection(&s_smallIdToSocketLock);
+ return sock;
+}
+
+void WinsockNetLayer::ClearSocketForSmallId(BYTE smallId)
+{
+ EnterCriticalSection(&s_smallIdToSocketLock);
+ s_smallIdToSocket[smallId] = INVALID_SOCKET;
+ LeaveCriticalSection(&s_smallIdToSocketLock);
+}
+
+// Send reject handshake: sentinel 0xFF + DisconnectPacket wire format (1 byte id 255 + 4 byte big-endian reason). Then caller closes socket.
+static void SendRejectWithReason(SOCKET clientSocket, DisconnectPacket::eDisconnectReason reason)
+{
+ BYTE buf[6];
+ buf[0] = WIN64_SMALLID_REJECT;
+ buf[1] = (BYTE)255; // DisconnectPacket packet id
+ int r = (int)reason;
+ buf[2] = (BYTE)((r >> 24) & 0xff);
+ buf[3] = (BYTE)((r >> 16) & 0xff);
+ buf[4] = (BYTE)((r >> 8) & 0xff);
+ buf[5] = (BYTE)(r & 0xff);
+ send(clientSocket, (const char*)buf, sizeof(buf), 0);
}
static bool RecvExact(SOCKET sock, BYTE* buf, int len)
@@ -440,6 +489,15 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
continue;
}
+ extern CPlatformNetworkManagerStub* g_pPlatformNetworkManager;
+ if (g_pPlatformNetworkManager != NULL && !g_pPlatformNetworkManager->CanAcceptMoreConnections())
+ {
+ app.DebugPrintf("Win64 LAN: Rejecting connection, server at max players\n");
+ SendRejectWithReason(clientSocket, DisconnectPacket::eDisconnect_ServerFull);
+ closesocket(clientSocket);
+ continue;
+ }
+
BYTE assignedSmallId;
EnterCriticalSection(&s_freeSmallIdLock);
if (!s_freeSmallIds.empty())
@@ -447,14 +505,15 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
assignedSmallId = s_freeSmallIds.back();
s_freeSmallIds.pop_back();
}
- else if (s_nextSmallId < MINECRAFT_NET_MAX_PLAYERS)
+ else if (s_nextSmallId < (unsigned int)MINECRAFT_NET_MAX_PLAYERS)
{
- assignedSmallId = s_nextSmallId++;
+ assignedSmallId = (BYTE)s_nextSmallId++;
}
else
{
LeaveCriticalSection(&s_freeSmallIdLock);
app.DebugPrintf("Win64 LAN: Server full, rejecting connection\n");
+ SendRejectWithReason(clientSocket, DisconnectPacket::eDisconnect_ServerFull);
closesocket(clientSocket);
continue;
}
@@ -482,6 +541,10 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
app.DebugPrintf("Win64 LAN: Client connected, assigned smallId=%d\n", assignedSmallId);
+ EnterCriticalSection(&s_smallIdToSocketLock);
+ s_smallIdToSocket[assignedSmallId] = clientSocket;
+ LeaveCriticalSection(&s_smallIdToSocketLock);
+
IQNetPlayer* qnetPlayer = &IQNet::m_player[assignedSmallId];
extern void Win64_SetupRemoteQNetPlayer(IQNetPlayer * player, BYTE smallId, bool isHost, bool isLocal);
@@ -724,6 +787,13 @@ void WinsockNetLayer::UpdateAdvertisePlayerCount(BYTE count)
LeaveCriticalSection(&s_advertiseLock);
}
+void WinsockNetLayer::UpdateAdvertiseMaxPlayers(BYTE maxPlayers)
+{
+ EnterCriticalSection(&s_advertiseLock);
+ s_advertiseData.maxPlayers = maxPlayers;
+ LeaveCriticalSection(&s_advertiseLock);
+}
+
void WinsockNetLayer::UpdateAdvertiseJoinable(bool joinable)
{
EnterCriticalSection(&s_advertiseLock);
diff --git a/Minecraft.Client/Windows64/Network/WinsockNetLayer.h b/Minecraft.Client/Windows64/Network/WinsockNetLayer.h
index fd1280f7..f30240d3 100644
--- a/Minecraft.Client/Windows64/Network/WinsockNetLayer.h
+++ b/Minecraft.Client/Windows64/Network/WinsockNetLayer.h
@@ -12,7 +12,8 @@
#pragma comment(lib, "Ws2_32.lib")
#define WIN64_NET_DEFAULT_PORT 25565
-#define WIN64_NET_MAX_CLIENTS 7
+#define WIN64_NET_MAX_CLIENTS 255
+#define WIN64_SMALLID_REJECT 0xFF
#define WIN64_NET_RECV_BUFFER_SIZE 65536
#define WIN64_NET_MAX_PACKET_SIZE (4 * 1024 * 1024)
#define WIN64_LAN_DISCOVERY_PORT 25566
@@ -89,6 +90,7 @@ public:
static bool StartAdvertising(int gamePort, const wchar_t* hostName, unsigned int gameSettings, unsigned int texPackId, unsigned char subTexId, unsigned short netVer);
static void StopAdvertising();
static void UpdateAdvertisePlayerCount(BYTE count);
+ static void UpdateAdvertiseMaxPlayers(BYTE maxPlayers);
static void UpdateAdvertiseJoinable(bool joinable);
static bool StartDiscovery();
@@ -116,7 +118,7 @@ private:
static BYTE s_localSmallId;
static BYTE s_hostSmallId;
- static BYTE s_nextSmallId;
+ static unsigned int s_nextSmallId;
static CRITICAL_SECTION s_sendLock;
static CRITICAL_SECTION s_connectionsLock;
@@ -141,6 +143,12 @@ private:
static CRITICAL_SECTION s_freeSmallIdLock;
static std::vector<BYTE> s_freeSmallIds;
+ // O(1) smallId -> socket lookup so we don't scan s_connections (which never shrinks) on every send
+ static SOCKET s_smallIdToSocket[256];
+ static CRITICAL_SECTION s_smallIdToSocketLock;
+
+public:
+ static void ClearSocketForSmallId(BYTE smallId);
};
extern bool g_Win64MultiplayerHost;