Skip to content

Commit c1f77ce

Browse files
committed
Improvements to connection handshake
1 parent da42f85 commit c1f77ce

7 files changed

Lines changed: 224 additions & 71 deletions

File tree

GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NetworkBitstream.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
enum EPacketID
88
{
99
PACKET_ID_NONE = -1,
10+
PACKET_ID_CHALLENGE,
11+
PACKET_ID_CHALLENGE_RESP,
1012
PACKET_ID_NET_ROOM_HELLO,
1113
PACKET_ID_NET_ROOM_HELLO_ACK,
1214
PACKET_ID_NET_ROOM_CHAT_MSG,

GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/NetworkMesh.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ class NetworkMesh
107107
{
108108
for (auto& connection : m_mapConnections)
109109
{
110-
if (connection.second.m_peer->address.host == peer->address.host)
110+
if (connection.second.m_peer->address.host == peer->address.host
111+
&& connection.second.m_peer->address.port == peer->address.port)
111112
{
112113
return &connection.second;
113114
}

GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/OnlineServices_LobbyInterface.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class NGMP_OnlineServices_LobbyInterface
120120
AsciiString m_PendingCreation_InitialMapPath;
121121
void CreateLobby(UnicodeString strLobbyName, UnicodeString strInitialMapName, AsciiString strInitialMapPath, bool bIsOfficial, int initialMaxSize, bool bVanillaTeamsOnly, bool bTrackStats, uint32_t startingCash, bool bPassworded, const char* szPassword);
122122

123-
void OnJoinedOrCreatedLobby(bool bAlreadyUpdatedDetails = false);
123+
void OnJoinedOrCreatedLobby(bool bAlreadyUpdatedDetails, std::function<void(void)> fnCallback);
124124

125125
UnicodeString GetCurrentLobbyDisplayName();
126126
UnicodeString GetCurrentLobbyMapDisplayName();

GeneralsMD/Code/GameEngine/Include/GameNetwork/GeneralsOnline/Packets/NetworkPacket_NetRoom_Hello.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,33 @@ class NetRoom_HelloPacket : public NetworkPacket
1313

1414
int64_t GetUserID() const { return m_user_id; }
1515

16+
private:
17+
int64_t m_user_id = -1;
18+
};
19+
20+
class Net_ChallengePacket : public NetworkPacket
21+
{
22+
public:
23+
Net_ChallengePacket();
24+
25+
Net_ChallengePacket(CBitStream& bitstream);
26+
27+
virtual CBitStream* Serialize() override;
28+
29+
private:
30+
};
31+
32+
class Net_ChallengeRespPacket : public NetworkPacket
33+
{
34+
public:
35+
Net_ChallengeRespPacket(int64_t myUserID);
36+
37+
Net_ChallengeRespPacket(CBitStream& bitstream);
38+
39+
virtual CBitStream* Serialize() override;
40+
41+
int64_t GetUserID() const { return m_user_id; }
42+
1643
private:
1744
int64_t m_user_id = -1;
1845
};

GeneralsMD/Code/GameEngine/Source/GameNetwork/GeneralsOnline/NetworkMesh.cpp

Lines changed: 114 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ void NetworkMesh::ConnectToSingleUser(ENetAddress addr, Int64 user_id, bool bIsR
160160
enet_address_set_host(&addr, "127.0.0.1");
161161
}
162162

163-
/* Initiate the connection, allocating the two channels 0 and 1. */
164-
ENetPeer* peer = enet_host_connect(enetInstance, &addr, 2, 0);
163+
/* Initiate the connection, allocating the 3 channels. */
164+
ENetPeer* peer = enet_host_connect(enetInstance, &addr, 3, 0);
165165

166166
if (peer == nullptr)
167167
{
@@ -219,7 +219,7 @@ void NetworkMesh::ConnectToMesh(LobbyEntry& lobby)
219219
// TODO_NGMP: Correct values here
220220
enetInstance = enet_host_create(&server_address,
221221
32, // max game size is 8 and we are p2p and fake a connection to ourselves // TODO_NGMP: Do we need to support more, e.g. spectators?
222-
2, // 2 channels, 0 is lobby, 1 is gameplay
222+
3, // 3 channels, 0 is lobby, 1 is gameplay, 2 is handshake
223223
0,
224224
0);
225225

@@ -301,18 +301,33 @@ void NetworkMesh::Tick()
301301
{
302302
case ENET_EVENT_TYPE_CONNECT:
303303
{
304+
// TODO_NGMP: Set a timeout where we remove it, and only accept hello if not connected
304305
char ip[INET_ADDRSTRLEN + 1] = { 0 };
305306
if (enet_address_get_host_ip(&event.peer->address, ip, sizeof(ip)) == 0)
306307
{
307-
NetworkLog("[SERVER] A new client connected from %s:%u.\n",
308+
NetworkLog("[SERVER] A new client connected from %s:%u. Starting wait for hello\n",
308309
ip,
309310
event.peer->address.port);
310311
}
311312

313+
// send challenge
314+
Net_ChallengePacket challengePacket;
315+
CBitStream* pBitStream = challengePacket.Serialize();
316+
pBitStream->Encrypt(currentLobby.EncKey, currentLobby.EncIV);
317+
318+
ENetPacket* pENetPacket = enet_packet_create((void*)pBitStream->GetRawBuffer(), pBitStream->GetNumBytesUsed(),
319+
ENET_PACKET_FLAG_RELIABLE);
320+
321+
enet_peer_send(event.peer, 2, pENetPacket);
322+
323+
324+
/*
312325
// find user
313326
// TODO_NGMP: What if it isnt found? could be an unauthorized user but could also be someone connecting before we know they're in the lobby
314327
PlayerConnection* pConnection = GetConnectionForPeer(event.peer);
315328
if (pConnection != nullptr)
329+
{
330+
if (pConnection->m_State != EConnectionState::CONNECTED_DIRECT)
316331
{
317332
NetworkLog("Found connection for user %d", pConnection->m_userID);
318333
@@ -332,14 +347,16 @@ void NetworkMesh::Tick()
332347
NetworkLog("Endpoint for user %lld changed. Before: %s:%d, now %s:%d", pConnection->m_userID, oldIp, pConnection->m_address.port, newIp, event.peer->address.port);
333348
pConnection->m_address = event.peer->address;
334349
pConnection->m_peer->address = event.peer->address;
335-
//
336-
// ENetAddress addr;
337-
// enet_address_set_host(&addr, newIp);
338-
// addr.port = event.peer->address.port;
339-
//
340-
// UpdatePeerConnection(event.peer, addr);
350+
//
351+
// ENetAddress addr;
352+
// enet_address_set_host(&addr, newIp);
353+
// addr.port = event.peer->address.port;
354+
//
355+
// UpdatePeerConnection(event.peer, addr);
341356
}
342357
}
358+
}
359+
*/
343360

344361
break;
345362
}
@@ -376,83 +393,133 @@ void NetworkMesh::Tick()
376393
}
377394
continue;
378395
}
379-
380-
// process
381-
// TODO_NGMP: Reject any packets from members not in the room? or mesh
382-
383-
384-
int64_t connUserID = -1;
385-
PlayerConnection* pConnection = GetConnectionForPeer(event.peer);
386-
387-
if (pConnection != nullptr)
396+
else if (event.channelID == 2) // handshake channel
388397
{
389-
connUserID = pConnection->m_userID;
390-
}
398+
CBitStream bitstream(event.packet->data, event.packet->dataLength, (EPacketID)event.packet->data[0]);
399+
NetworkLog("[NGMP]: Received %d bytes from peer %d on handshake channel", event.packet->dataLength, event.peer->incomingPeerID);
391400

392-
CBitStream bitstream(event.packet->data, event.packet->dataLength, (EPacketID)event.packet->data[0]);
393-
NetworkLog("[NGMP]: Received %d bytes from peer %d (user id is %lld)", event.packet->dataLength, event.peer->incomingPeerID, connUserID);
394401

395-
396-
bitstream.Decrypt(currentLobby.EncKey, currentLobby.EncIV);
402+
bitstream.Decrypt(currentLobby.EncKey, currentLobby.EncIV);
397403

398-
EPacketID packetID = bitstream.Read<EPacketID>();
404+
EPacketID packetID = bitstream.Read<EPacketID>();
399405

400-
// Game Mesh / Lobby packets only
401-
if (m_meshType == ENetworkMeshType::GAME_LOBBY)
402-
{
403-
// TODO_NGMP: Determine this all on connect instead of with a handshake, or keep the handshake for hole punching...
404-
if (packetID == EPacketID::PACKET_ID_NET_ROOM_HELLO)
406+
if (packetID == EPacketID::PACKET_ID_CHALLENGE) // remote host is challenging us
405407
{
406-
407408
// server sends hello ack in response to hello
408409
char ip[INET_ADDRSTRLEN + 1] = { 0 };
409410
enet_address_get_host_ip(&event.peer->address, ip, sizeof(ip));
410411

411-
NetRoom_HelloPacket helloPacket(bitstream);
412+
Net_ChallengePacket challengePacket(bitstream);
412413

413-
NetworkLog("[NGMP]: Got hello from %s:%d (user ID: %d), sending ack", ip, event.peer->address.port, helloPacket.GetUserID());
414+
NetworkLog("[NGMP]: Got challenge req from %s:%d, sending challenge resp", ip, event.peer->address.port);
414415

415416
// just send manually to that one user, dont broadcast
416-
NetRoom_HelloAckPacket ackPacket(NGMP_OnlineServicesManager::GetInstance()->GetAuthInterface()->GetUserID());
417-
CBitStream* pBitStream = ackPacket.Serialize();
417+
Net_ChallengeRespPacket challengeRespPacket(NGMP_OnlineServicesManager::GetInstance()->GetAuthInterface()->GetUserID());
418+
CBitStream* pBitStream = challengeRespPacket.Serialize();
418419

419420
pBitStream->Encrypt(currentLobby.EncKey, currentLobby.EncIV);
420421

421422
ENetPacket* pENetPacket = enet_packet_create((void*)pBitStream->GetRawBuffer(), pBitStream->GetNumBytesUsed(),
422-
ENET_PACKET_FLAG_RELIABLE); // TODO_NGMP: Support flags
423+
ENET_PACKET_FLAG_RELIABLE);
424+
425+
int ret = enet_peer_send(event.peer, 2, pENetPacket);
423426

424-
int ret = enet_peer_send(event.peer, 0, pENetPacket);
425427
if (ret == 0)
426428
{
427429
NetworkLog("Packet Sent!");
428430

429431
// TODO_NGMP: Have a full handshake here, dont just assume we're connected because we sent an ack
430432
// store the connection
431-
m_mapConnections[helloPacket.GetUserID()] = PlayerConnection(helloPacket.GetUserID(), event.peer->address, event.peer);
433+
//m_mapConnections[helloPacket.GetUserID()] = PlayerConnection(helloPacket.GetUserID(), event.peer->address, event.peer);
432434

433-
NetworkLog("[NGMP]: Registered connection for user %s:%d (user ID: %d)", ip, event.peer->address.port, helloPacket.GetUserID());
435+
//NetworkLog("[NGMP]: Registered connection for user %s:%d (user ID: %d)", ip, event.peer->address.port, helloPacket.GetUserID());
434436
}
435437
else
436438
{
437439
NetworkLog("Packet Failed To Send!");
438440
}
439441
}
440-
else if (packetID == EPacketID::PACKET_ID_NET_ROOM_HELLO_ACK)
442+
else if (packetID == EPacketID::PACKET_ID_CHALLENGE_RESP)
441443
{
442-
NetRoom_HelloAckPacket helloAckPacket(bitstream);
444+
Net_ChallengeRespPacket challengeRespPacket(bitstream);
443445

444446
char ip[INET_ADDRSTRLEN + 1] = { 0 };
445447
enet_address_get_host_ip(&event.peer->address, ip, sizeof(ip));
446-
NetworkLog("[NGMP]: Received ack from %s (user ID: %d), we're now connected", ip, helloAckPacket.GetUserID());
448+
NetworkLog("[NGMP]: Received ack from %s (user ID: %d), we're now connected", ip, challengeRespPacket.GetUserID());
447449

448450
// TODO_NGMP: Have a full handshake here, dont just assume we're connected because we sent an ack
449451
// store the connection
450-
m_mapConnections[helloAckPacket.GetUserID()] = PlayerConnection(helloAckPacket.GetUserID(), event.peer->address, event.peer);
452+
m_mapConnections[challengeRespPacket.GetUserID()] = PlayerConnection(challengeRespPacket.GetUserID(), event.peer->address, event.peer);
453+
m_mapConnections[challengeRespPacket.GetUserID()].m_State = EConnectionState::CONNECTED_DIRECT;
454+
455+
NetworkLog("[NGMP]: Registered client connection for user %s:%d (user ID: %d)", ip, event.peer->address.port, challengeRespPacket.GetUserID());
451456

452-
NetworkLog("[NGMP]: Registered client connection for user %s:%d (user ID: %d)", ip, event.peer->address.port, helloAckPacket.GetUserID());
457+
/*
458+
// find user
459+
// TODO_NGMP: What if it isnt found? could be an unauthorized user but could also be someone connecting before we know they're in the lobby
460+
PlayerConnection* pConnection = GetConnectionForPeer(event.peer);
461+
if (pConnection != nullptr)
462+
{
463+
if (pConnection->m_State != EConnectionState::CONNECTED_DIRECT)
464+
{
465+
NetworkLog("Found connection for user %d", pConnection->m_userID);
466+
467+
// TODO_NGMP: Add a timeout for connections
468+
pConnection->m_State = EConnectionState::CONNECTED_DIRECT;
469+
470+
// did the endpoint change? we should just use that, thats what the other side is talking to us on
471+
if (pConnection->m_address.host != event.peer->address.host
472+
|| pConnection->m_address.port != event.peer->address.port)
473+
{
474+
char oldIp[INET_ADDRSTRLEN + 1] = { 0 };
475+
enet_address_get_host_ip(&pConnection->m_address, oldIp, sizeof(oldIp));
476+
char newIp[INET_ADDRSTRLEN + 1] = { 0 };
477+
enet_address_get_host_ip(&event.peer->address, newIp, sizeof(newIp));
478+
479+
480+
NetworkLog("Endpoint for user %lld changed. Before: %s:%d, now %s:%d", pConnection->m_userID, oldIp, pConnection->m_address.port, newIp, event.peer->address.port);
481+
pConnection->m_address = event.peer->address;
482+
pConnection->m_peer->address = event.peer->address;
483+
//
484+
// ENetAddress addr;
485+
// enet_address_set_host(&addr, newIp);
486+
// addr.port = event.peer->address.port;
487+
//
488+
// UpdatePeerConnection(event.peer, addr);
489+
}
490+
}
491+
}
492+
*/
453493
}
454-
455-
else if (packetID == EPacketID::PACKET_ID_LOBBY_START_GAME)
494+
495+
continue;
496+
}
497+
498+
// process
499+
// TODO_NGMP: Reject any packets from members not in the room? or mesh
500+
501+
502+
int64_t connUserID = -1;
503+
PlayerConnection* pConnection = GetConnectionForPeer(event.peer);
504+
505+
if (pConnection != nullptr)
506+
{
507+
connUserID = pConnection->m_userID;
508+
}
509+
510+
CBitStream bitstream(event.packet->data, event.packet->dataLength, (EPacketID)event.packet->data[0]);
511+
NetworkLog("[NGMP]: Received %d bytes from peer %d (user id is %lld)", event.packet->dataLength, event.peer->incomingPeerID, connUserID);
512+
513+
514+
bitstream.Decrypt(currentLobby.EncKey, currentLobby.EncIV);
515+
516+
EPacketID packetID = bitstream.Read<EPacketID>();
517+
518+
// Game Mesh / Lobby packets only
519+
if (m_meshType == ENetworkMeshType::GAME_LOBBY)
520+
{
521+
// TODO_NGMP: Determine this all on connect instead of with a handshake, or keep the handshake for hole punching...
522+
if (packetID == EPacketID::PACKET_ID_LOBBY_START_GAME)
456523
{
457524
// TODO_NGMP: Ignore if not host sending
458525
NetworkLog("[NGMP]: Got start game packet from %d", event.peer->incomingPeerID);

0 commit comments

Comments
 (0)