added better handling of network connections:
- only listen for new clients on a server if an open slot exists (unconnected) - for both server and client we wait a max of 10 seconds to receive a proper intro packet or we disconnect (could have connected to / from a non glest application using the same port)
This commit is contained in:
parent
d064b52418
commit
319b672e20
|
@ -39,6 +39,7 @@ public:
|
|||
static const int cameraFps= 100;
|
||||
static const int networkFramePeriod= 10;
|
||||
static const int networkExtraLatency= 200;
|
||||
static const int maxClientConnectHandshakeSecs= 10;
|
||||
|
||||
static const char *folder_path_maps;
|
||||
static const char *folder_path_scenarios;
|
||||
|
|
|
@ -44,6 +44,7 @@ ClientInterface::ClientInterface(){
|
|||
introDone= false;
|
||||
playerIndex= -1;
|
||||
gameSettingsReceived=false;
|
||||
gotIntro = false;
|
||||
|
||||
networkGameDataSynchCheckOkMap = false;
|
||||
networkGameDataSynchCheckOkTile = false;
|
||||
|
@ -78,6 +79,7 @@ void ClientInterface::connect(const Ip &ip, int port)
|
|||
clientSocket= new ClientSocket();
|
||||
clientSocket->setBlock(false);
|
||||
clientSocket->connect(ip, port);
|
||||
connectedTime = time(NULL);
|
||||
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END - socket = %d\n",__FILE__,__FUNCTION__,clientSocket->getSocketId());
|
||||
}
|
||||
|
@ -133,13 +135,13 @@ void ClientInterface::updateLobby()
|
|||
{
|
||||
NetworkMessageIntro networkMessageIntro;
|
||||
|
||||
if(receiveMessage(&networkMessageIntro))
|
||||
{
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got NetworkMessageIntro\n",__FILE__,__FUNCTION__);
|
||||
if(receiveMessage(&networkMessageIntro)) {
|
||||
gotIntro = true;
|
||||
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got NetworkMessageIntro, networkMessageIntro.getGameState() = %d\n",__FILE__,__FUNCTION__,networkMessageIntro.getGameState());
|
||||
|
||||
//check consistency
|
||||
if(networkMessageIntro.getVersionString() != getNetworkVersionString())
|
||||
{
|
||||
if(networkMessageIntro.getVersionString() != getNetworkVersionString()) {
|
||||
bool versionMatched = false;
|
||||
string platformFreeVersion = getNetworkPlatformFreeVersionString();
|
||||
string sErr = "";
|
||||
|
@ -165,8 +167,8 @@ void ClientInterface::updateLobby()
|
|||
sendTextMessage(" Client: "+ getNetworkVersionString(),-1);
|
||||
}
|
||||
|
||||
if(Config::getInstance().getBool("PlatformConsistencyChecks","true") && versionMatched == false)
|
||||
{// error message and disconnect only if checked
|
||||
if(Config::getInstance().getBool("PlatformConsistencyChecks","true") &&
|
||||
versionMatched == false) { // error message and disconnect only if checked
|
||||
DisplayErrorMessage(sErr);
|
||||
quit= true;
|
||||
close();
|
||||
|
@ -174,15 +176,31 @@ void ClientInterface::updateLobby()
|
|||
}
|
||||
}
|
||||
|
||||
//send intro message
|
||||
NetworkMessageIntro sendNetworkMessageIntro(getNetworkVersionString(), Config::getInstance().getString("NetPlayerName",Socket::getHostName().c_str()), -1);
|
||||
if(networkMessageIntro.getGameState() == nmgstOk) {
|
||||
//send intro message
|
||||
NetworkMessageIntro sendNetworkMessageIntro(getNetworkVersionString(), Config::getInstance().getString("NetPlayerName",Socket::getHostName().c_str()), -1, nmgstOk);
|
||||
|
||||
playerIndex= networkMessageIntro.getPlayerIndex();
|
||||
serverName= networkMessageIntro.getName();
|
||||
sendMessage(&sendNetworkMessageIntro);
|
||||
playerIndex= networkMessageIntro.getPlayerIndex();
|
||||
serverName= networkMessageIntro.getName();
|
||||
sendMessage(&sendNetworkMessageIntro);
|
||||
|
||||
assert(playerIndex>=0 && playerIndex<GameConstants::maxPlayers);
|
||||
introDone= true;
|
||||
assert(playerIndex>=0 && playerIndex<GameConstants::maxPlayers);
|
||||
introDone= true;
|
||||
}
|
||||
else if(networkMessageIntro.getGameState() == nmgstNoSlots) {
|
||||
string sErr = "Cannot join the server because there are no open slots for new players.";
|
||||
DisplayErrorMessage(sErr);
|
||||
quit= true;
|
||||
close();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
string sErr = "Unknown response from server: " + intToStr(networkMessageIntro.getGameState());
|
||||
DisplayErrorMessage(sErr);
|
||||
quit= true;
|
||||
close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -399,6 +417,11 @@ void ClientInterface::updateLobby()
|
|||
close();
|
||||
}
|
||||
}
|
||||
|
||||
if(gotIntro == false && difftime(time(NULL),connectedTime) > GameConstants::maxClientConnectHandshakeSecs) {
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] difftime(time(NULL),connectedTime) = %d\n",__FILE__,__FUNCTION__,__LINE__,difftime(time(NULL),connectedTime));
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void ClientInterface::updateKeyframe(int frameCount)
|
||||
|
@ -699,6 +722,9 @@ void ClientInterface::close()
|
|||
|
||||
delete clientSocket;
|
||||
clientSocket= NULL;
|
||||
|
||||
connectedTime = 0;
|
||||
gotIntro = false;
|
||||
}
|
||||
|
||||
void ClientInterface::discoverServers(DiscoveredServersInterface *cb) {
|
||||
|
|
|
@ -42,6 +42,8 @@ private:
|
|||
bool launchGame;
|
||||
int playerIndex;
|
||||
bool gameSettingsReceived;
|
||||
time_t connectedTime;
|
||||
bool gotIntro;
|
||||
|
||||
Ip ip;
|
||||
int port;
|
||||
|
|
|
@ -39,6 +39,7 @@ ConnectionSlot::ConnectionSlot(ServerInterface* serverInterface, int playerIndex
|
|||
this->playerIndex= playerIndex;
|
||||
socket= NULL;
|
||||
ready= false;
|
||||
gotIntro = false;
|
||||
|
||||
networkGameDataSynchCheckOkMap = false;
|
||||
networkGameDataSynchCheckOkTile = false;
|
||||
|
@ -77,20 +78,36 @@ void ConnectionSlot::update(bool checkForNewClients)
|
|||
//if(serverInterface->getServerSocket()->isReadable() == true)
|
||||
if(checkForNewClients == true)
|
||||
{
|
||||
socket = serverInterface->getServerSocket()->accept();
|
||||
//SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] BEFORE accept new client connection, serverInterface->getOpenSlotCount() = %d\n",__FILE__,__FUNCTION__,serverInterface->getOpenSlotCount());
|
||||
bool hasOpenSlots = (serverInterface->getOpenSlotCount() > 0);
|
||||
if(serverInterface->getServerSocket()->hasDataToRead() == true) {
|
||||
socket = serverInterface->getServerSocket()->accept();
|
||||
serverInterface->updateListen();
|
||||
}
|
||||
//send intro message when connected
|
||||
if(socket != NULL) {
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] accepted new client connection, serverInterface->getOpenSlotCount() = %d\n",__FILE__,__FUNCTION__,serverInterface->getOpenSlotCount());
|
||||
connectedTime = time(NULL);
|
||||
|
||||
//send intro message when connected
|
||||
if(socket != NULL)
|
||||
{
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] accepted new client connection\n",__FILE__,__FUNCTION__);
|
||||
chatText.clear();
|
||||
chatSender.clear();
|
||||
chatTeamIndex= -1;
|
||||
|
||||
chatText.clear();
|
||||
chatSender.clear();
|
||||
chatTeamIndex= -1;
|
||||
if(hasOpenSlots == false) {
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] no open slots, disconnecting client\n",__FILE__,__FUNCTION__);
|
||||
|
||||
NetworkMessageIntro networkMessageIntro(getNetworkVersionString(), socket->getHostName(), playerIndex);
|
||||
sendMessage(&networkMessageIntro);
|
||||
}
|
||||
NetworkMessageIntro networkMessageIntro(getNetworkVersionString(), socket->getHostName(), playerIndex, nmgstNoSlots);
|
||||
sendMessage(&networkMessageIntro);
|
||||
|
||||
close();
|
||||
}
|
||||
else {
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] client will be assigned to the next open slot\n",__FILE__,__FUNCTION__);
|
||||
|
||||
NetworkMessageIntro networkMessageIntro(getNetworkVersionString(), socket->getHostName(), playerIndex, nmgstOk);
|
||||
sendMessage(&networkMessageIntro);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -144,12 +161,12 @@ void ConnectionSlot::update(bool checkForNewClients)
|
|||
//process intro messages
|
||||
case nmtIntro:
|
||||
{
|
||||
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtIntro\n",__FILE__,__FUNCTION__);
|
||||
|
||||
NetworkMessageIntro networkMessageIntro;
|
||||
if(receiveMessage(&networkMessageIntro))
|
||||
{
|
||||
gotIntro = true;
|
||||
name= networkMessageIntro.getName();
|
||||
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got name [%s]\n",__FILE__,__FUNCTION__,name.c_str());
|
||||
|
@ -189,11 +206,7 @@ void ConnectionSlot::update(bool checkForNewClients)
|
|||
}
|
||||
|
||||
//tileset
|
||||
//world.loadTileset(config.getPathListForType(ptTilesets,scenarioDir), tilesetName, &checksum);
|
||||
|
||||
//int32 tilesetCRC = getFolderTreeContentsCheckSumRecursively(string(GameConstants::folder_path_tilesets) + "/" + serverInterface->getGameSettings()->getTileset() + "/*", ".xml", NULL);
|
||||
int32 tilesetCRC = getFolderTreeContentsCheckSumRecursively(config.getPathListForType(ptTilesets,scenarioDir), string("/") + serverInterface->getGameSettings()->getTileset() + string("/*"), ".xml", NULL);
|
||||
//int32 techCRC = getFolderTreeContentsCheckSumRecursively(string(GameConstants::folder_path_techs) + "/" + serverInterface->getGameSettings()->getTech() + "/*", ".xml", NULL);
|
||||
int32 techCRC = getFolderTreeContentsCheckSumRecursively(config.getPathListForType(ptTechs,scenarioDir), "/" + serverInterface->getGameSettings()->getTech() + "/*", ".xml", NULL);
|
||||
Checksum checksum;
|
||||
string file = Map::getMapPath(serverInterface->getGameSettings()->getMap(),scenarioDir);
|
||||
|
@ -342,6 +355,11 @@ void ConnectionSlot::update(bool checkForNewClients)
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(gotIntro == false && difftime(time(NULL),connectedTime) > GameConstants::maxClientConnectHandshakeSecs) {
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] difftime(time(NULL),connectedTime) = %d\n",__FILE__,__FUNCTION__,__LINE__,difftime(time(NULL),connectedTime));
|
||||
close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -362,6 +380,10 @@ void ConnectionSlot::close()
|
|||
chatText.clear();
|
||||
chatSender.clear();
|
||||
chatTeamIndex= -1;
|
||||
ready = false;
|
||||
gotIntro = false;
|
||||
|
||||
serverInterface->updateListen();
|
||||
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END\n",__FILE__,__FUNCTION__);
|
||||
}
|
||||
|
|
|
@ -13,10 +13,9 @@
|
|||
#define _GLEST_GAME_CONNECTIONSLOT_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "socket.h"
|
||||
|
||||
#include "network_interface.h"
|
||||
#include <time.h>
|
||||
|
||||
using Shared::Platform::ServerSocket;
|
||||
using Shared::Platform::Socket;
|
||||
|
@ -39,6 +38,8 @@ private:
|
|||
bool ready;
|
||||
vector<std::pair<string,int32> > vctFileList;
|
||||
bool receivedNetworkGameStatus;
|
||||
time_t connectedTime;
|
||||
bool gotIntro;
|
||||
|
||||
public:
|
||||
ConnectionSlot(ServerInterface* serverInterface, int playerIndex);
|
||||
|
|
|
@ -119,13 +119,15 @@ void NetworkMessage::send(Socket* socket, const void* data, int dataSize) const
|
|||
NetworkMessageIntro::NetworkMessageIntro(){
|
||||
data.messageType= -1;
|
||||
data.playerIndex= -1;
|
||||
data.gameState = nmgstInvalid;
|
||||
}
|
||||
|
||||
NetworkMessageIntro::NetworkMessageIntro(const string &versionString, const string &name, int playerIndex){
|
||||
data.messageType=nmtIntro;
|
||||
data.versionString= versionString;
|
||||
data.name= name;
|
||||
data.playerIndex= static_cast<int16>(playerIndex);
|
||||
NetworkMessageIntro::NetworkMessageIntro(const string &versionString, const string &name, int playerIndex, NetworkGameStateType gameState) {
|
||||
data.messageType = nmtIntro;
|
||||
data.versionString = versionString;
|
||||
data.name = name;
|
||||
data.playerIndex = static_cast<int16>(playerIndex);
|
||||
data.gameState = static_cast<int8>(gameState);
|
||||
}
|
||||
|
||||
bool NetworkMessageIntro::receive(Socket* socket){
|
||||
|
|
|
@ -45,6 +45,14 @@ enum NetworkMessageType {
|
|||
nmtCount
|
||||
};
|
||||
|
||||
enum NetworkGameStateType {
|
||||
nmgstInvalid,
|
||||
nmgstOk,
|
||||
nmgstNoSlots,
|
||||
|
||||
nmgstCount
|
||||
};
|
||||
|
||||
const int32 commandListHeaderSize = 6;
|
||||
|
||||
// =====================================================
|
||||
|
@ -81,6 +89,7 @@ private:
|
|||
NetworkString<maxVersionStringSize> versionString;
|
||||
NetworkString<maxNameSize> name;
|
||||
int16 playerIndex;
|
||||
int8 gameState;
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -88,11 +97,12 @@ private:
|
|||
|
||||
public:
|
||||
NetworkMessageIntro();
|
||||
NetworkMessageIntro(const string &versionString, const string &name, int playerIndex);
|
||||
NetworkMessageIntro(const string &versionString, const string &name, int playerIndex, NetworkGameStateType gameState);
|
||||
|
||||
string getVersionString() const {return data.versionString.getString();}
|
||||
string getName() const {return data.name.getString();}
|
||||
int getPlayerIndex() const {return data.playerIndex;}
|
||||
string getVersionString() const { return data.versionString.getString(); }
|
||||
string getName() const { return data.name.getString(); }
|
||||
int getPlayerIndex() const { return data.playerIndex; }
|
||||
NetworkGameStateType getGameState() const { return static_cast<NetworkGameStateType>(data.gameState); }
|
||||
|
||||
virtual bool receive(Socket* socket);
|
||||
virtual void send(Socket* socket) const;
|
||||
|
|
|
@ -602,7 +602,6 @@ void ServerInterface::broadcastMessageToConnectedClients(const NetworkMessage* n
|
|||
void ServerInterface::updateListen()
|
||||
{
|
||||
int openSlotCount= 0;
|
||||
|
||||
for(int i= 0; i<GameConstants::maxPlayers; ++i)
|
||||
{
|
||||
if(slots[i] != NULL && slots[i]->isConnected() == false)
|
||||
|
@ -614,6 +613,20 @@ void ServerInterface::updateListen()
|
|||
serverSocket.listen(openSlotCount);
|
||||
}
|
||||
|
||||
int ServerInterface::getOpenSlotCount() {
|
||||
int openSlotCount= 0;
|
||||
|
||||
for(int i= 0; i<GameConstants::maxPlayers; ++i)
|
||||
{
|
||||
if(slots[i] != NULL && slots[i]->isConnected() == false)
|
||||
{
|
||||
++openSlotCount;
|
||||
}
|
||||
}
|
||||
|
||||
return openSlotCount;
|
||||
}
|
||||
|
||||
void ServerInterface::setGameSettings(GameSettings *serverGameSettings, bool waitForClientAck)
|
||||
{
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] START gameSettingsUpdateCount = %d, waitForClientAck = %d\n",__FILE__,__FUNCTION__,gameSettingsUpdateCount,waitForClientAck);
|
||||
|
|
|
@ -73,14 +73,15 @@ public:
|
|||
void removeSlot(int playerIndex);
|
||||
ConnectionSlot* getSlot(int playerIndex);
|
||||
int getConnectedSlotCount();
|
||||
int getOpenSlotCount();
|
||||
|
||||
bool launchGame(const GameSettings* gameSettings);
|
||||
virtual void setGameSettings(GameSettings *serverGameSettings, bool waitForClientAck = false);
|
||||
void broadcastGameSetup(const GameSettings* gameSettings);
|
||||
void updateListen();
|
||||
|
||||
private:
|
||||
void broadcastMessage(const NetworkMessage* networkMessage, int excludeSlot= -1);
|
||||
void updateListen();
|
||||
void broadcastMessageToConnectedClients(const NetworkMessage* networkMessage, int excludeSlot = -1);
|
||||
bool shouldDiscardNetworkMessage(NetworkMessageType networkMessageType,ConnectionSlot* connectionSlot);
|
||||
};
|
||||
|
|
|
@ -181,6 +181,7 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
int boundPort;
|
||||
BroadCastSocketThread *broadCastThread;
|
||||
void startBroadCastThread();
|
||||
bool isBroadCastThreadRunning();
|
||||
|
|
|
@ -1504,6 +1504,7 @@ bool ServerSocket::isBroadCastThreadRunning() {
|
|||
|
||||
void ServerSocket::bind(int port)
|
||||
{
|
||||
boundPort = port;
|
||||
//sockaddr structure
|
||||
sockaddr_in addr;
|
||||
addr.sin_family= AF_INET;
|
||||
|
@ -1527,14 +1528,31 @@ void ServerSocket::bind(int port)
|
|||
}
|
||||
}
|
||||
|
||||
void ServerSocket::listen(int connectionQueueSize)
|
||||
{
|
||||
int err= ::listen(sock, connectionQueueSize);
|
||||
if(err < 0)
|
||||
{
|
||||
char szBuf[1024]="";
|
||||
sprintf(szBuf, "In [%s::%s] Error listening socket sock = %d, err = %d, error = %s\n",__FILE__,__FUNCTION__,sock,err,getLastSocketErrorFormattedText().c_str());
|
||||
throwException(szBuf);
|
||||
void ServerSocket::listen(int connectionQueueSize) {
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d connectionQueueSize = %d\n",__FILE__,__FUNCTION__,__LINE__,connectionQueueSize);
|
||||
|
||||
if(connectionQueueSize > 0) {
|
||||
if(isSocketValid() == false) {
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if(isSocketValid() == false) {
|
||||
throwException("Error creating socket");
|
||||
}
|
||||
setBlock(false);
|
||||
bind(boundPort);
|
||||
}
|
||||
|
||||
int err= ::listen(sock, connectionQueueSize);
|
||||
if(err < 0) {
|
||||
char szBuf[1024]="";
|
||||
sprintf(szBuf, "In [%s::%s] Error listening socket sock = %d, err = %d, error = %s\n",__FILE__,__FUNCTION__,sock,err,getLastSocketErrorFormattedText().c_str());
|
||||
throwException(szBuf);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||
disconnectSocket();
|
||||
}
|
||||
|
||||
if(connectionQueueSize > 0) {
|
||||
|
@ -1545,7 +1563,6 @@ void ServerSocket::listen(int connectionQueueSize)
|
|||
else {
|
||||
stopBroadCastThread();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Socket *ServerSocket::accept()
|
||||
|
@ -1555,6 +1572,7 @@ Socket *ServerSocket::accept()
|
|||
{
|
||||
char szBuf[1024]="";
|
||||
sprintf(szBuf, "In [%s::%s] Error accepting socket connection sock = %d, err = %d, error = %s\n",__FILE__,__FUNCTION__,sock,newSock,getLastSocketErrorFormattedText().c_str());
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,szBuf);
|
||||
|
||||
if(getLastSocketError() == PLATFORM_SOCKET_TRY_AGAIN)
|
||||
{
|
||||
|
@ -1563,6 +1581,9 @@ Socket *ServerSocket::accept()
|
|||
throwException(szBuf);
|
||||
|
||||
}
|
||||
else {
|
||||
SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got connection, newSock = %d\n",__FILE__,__FUNCTION__,__LINE__,newSock);
|
||||
}
|
||||
return new Socket(newSock);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue