| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595 |
- //
- // Created by Keith Johnston on 4/16/16.
- //
- #include "MasterServerClient.h"
- #include "../Precompiled.h"
- #include "../IO/Log.h"
- #include "../Network/NetworkPriority.h"
- #include "../Network/Network.h"
- #include "../Core/Profiler.h"
- #include "../Core/CoreEvents.h"
- #include "../Network/NetworkEvents.h"
- #include <rapidjson/document.h>
- #include <rapidjson/stringbuffer.h>
- #include <rapidjson/prettywriter.h>
- namespace Atomic
- {
- MasterServerClient::MasterServerClient(Context *context) :
- readingMasterMessageLength(true),
- Object(context),
- udpSecondsTillRetry_(0.5f),
- connectToMasterState_(MASTER_NOT_CONNECTED),
- clientConnectToGameServerState_(GAME_NOT_CONNECTED),
- timeBetweenClientPunchThroughAttempts_(1.0),
- timeTillNextPunchThroughAttempt_(0.0),
- timeBetweenClientConnectAttempts_(1.0),
- timeTillNextClientConnectAttempt_(1.0),
- masterTCPConnection_(NULL),
- clientToServerSocket_(NULL)
- {
- SubscribeToEvent(E_BEGINFRAME, HANDLER(MasterServerClient, HandleBeginFrame));
- }
- MasterServerClient::~MasterServerClient()
- {
- if (masterTCPConnection_)
- {
- masterTCPConnection_->Disconnect();
- }
- }
- void MasterServerClient::ConnectToMaster(const String &address, unsigned short port)
- {
- PROFILE(ConnectToMaster);
- if (connectToMasterState_ != MASTER_NOT_CONNECTED)
- {
- DisconnectFromMaster();
- }
- masterServerInfo_.address = address;
- masterServerInfo_.port = port;
- masterServerInfo_.isRegisteringServer = false;
- // We first make a TCP connection
- SetConnectToMasterState(MASTER_CONNECTING_TCP);
- }
- void MasterServerClient::DisconnectFromMaster()
- {
- masterTCPConnection_->Disconnect();
- masterUDPConnection_->Disconnect();
- SetConnectToMasterState(MASTER_NOT_CONNECTED);
- }
- void MasterServerClient::ConnectToMasterAndRegister(const String &address, unsigned short port, const String& serverName)
- {
- PROFILE(ConnectToMaster);
- if (connectToMasterState_ != MASTER_NOT_CONNECTED)
- {
- DisconnectFromMaster();
- }
- masterServerInfo_.address = address;
- masterServerInfo_.port = port;
- masterServerInfo_.serverName = serverName;
- masterServerInfo_.isRegisteringServer = true;
- // We first make a TCP connection
- SetConnectToMasterState(MASTER_CONNECTING_TCP);
- }
- void MasterServerClient::RequestServerListFromMaster()
- {
- SendMessageToMasterServer("{ \"cmd\": \"getServerList\" }");
- }
- void MasterServerClient::ConnectToServerViaMaster(const String &serverId,
- const String &internalAddress, unsigned short internalPort,
- const String &externalAddress, unsigned short externalPort,
- Scene* scene)
- {
- remoteGameServerInfo_.serverId = serverId;
- remoteGameServerInfo_.internalAddress = internalAddress;
- remoteGameServerInfo_.internalPort = internalPort;
- remoteGameServerInfo_.externalAddress = externalAddress;
- remoteGameServerInfo_.externalPort = externalPort;
- remoteGameServerInfo_.clientScene = scene;
- SetConnectToGameServerState(GAME_CONNECTING_INTERNAL_IP);
- }
- void MasterServerClient::RegisterServerWithMaster(const String &name)
- {
- // Get the internal IP and port
- kNet::EndPoint localEndPoint = masterTCPConnection_->LocalEndPoint();
- unsigned char* ip = localEndPoint.ip;
- char str[256];
- sprintf(str, "%d.%d.%d.%d", (unsigned int)ip[0], (unsigned int)ip[1], (unsigned int)ip[2], (unsigned int)ip[3]);
- Atomic::Network* network = GetSubsystem<Network>();
- // FIXME
- unsigned int localPort = 9;//network->GetServerPort();
- String msg = String("{") +
- String("\"cmd\":") + String("\"registerServer\",") +
- String("\"internalIP\": \"") + String(str) + String("\", ") +
- String("\"internalPort\": ") + String(localPort) + String(", ") +
- String("\"id\":\"") + masterServerConnectionId_ + String("\", ") +
- String("\"serverName\":\"") + name + String("\"") +
- String("}");
- SendMessageToMasterServer(msg);
- }
- void MasterServerClient::SendMessageToMasterServer(const String& msg)
- {
- if (masterTCPConnection_)
- {
- String netString = String(msg.Length()) + ':' + msg;
- masterTCPConnection_->Send(netString.CString(), netString.Length());
- }
- else
- {
- LOGERROR("No master server connection. Cannot send message");
- }
- }
- void MasterServerClient::Update(float dt)
- {
- if (masterTCPConnection_==NULL)
- {
- return;
- }
- CheckForMessageFromMaster();
- ConnectToMasterUpdate(dt);
- ConnectToGameServerUpdate(dt);
- CheckForNatPunchThroughRequests(dt);
- }
- void MasterServerClient::CheckForNatPunchThroughRequests(float dt)
- {
- if (clientIdToPunchThroughSocketMap_.Size() > 0)
- {
- if (timeTillNextPunchThroughAttempt_ <= 0)
- {
- for (HashMap<String, kNet::Socket*>::Iterator i = clientIdToPunchThroughSocketMap_.Begin();
- i != clientIdToPunchThroughSocketMap_.End();)
- {
- Network* network = GetSubsystem<Network>();
- LOGINFO("Sending packet to client");
- kNet::Socket* s = i->second_;
- if (network->IsEndPointConnected(s->RemoteEndPoint()))
- {
- i = clientIdToPunchThroughSocketMap_.Erase(i);
- }
- else
- {
- s->Send("K",1);
- ++i;
- }
- }
- // Reset the timer
- timeTillNextPunchThroughAttempt_ = timeBetweenClientPunchThroughAttempts_;
- }
- timeTillNextPunchThroughAttempt_ -= dt;
- }
- // See if we need to still be trying to punch through from the client
- if (clientConnectToGameServerState_ == GAME_CONNECTING_EXTERNAL_IP &&
- clientToServerSocket_ != NULL && timeTillNextClientConnectAttempt_ <= 0)
- {
- Atomic::Network* network = GetSubsystem<Network>();
- if (!network->GetServerConnection() || !network->GetServerConnection()->IsConnected())
- {
- LOGINFO("Sending packet to server");
- clientToServerSocket_->Send("K",1);
- }
- timeTillNextClientConnectAttempt_ = timeBetweenClientConnectAttempts_;
- }
- timeTillNextClientConnectAttempt_ -= dt;
- }
- void MasterServerClient::CheckForMessageFromMaster()
- {
- kNet::OverlappedTransferBuffer *buf = masterTCPConnection_->BeginReceive();
- if (buf && buf->bytesContains > 0) {
- int n = 0;
- int totalBytes = buf->bytesContains;
- while (n < totalBytes) {
- char c = buf->buffer.buf[n++];
- // Are we still reading in the length?
- if (readingMasterMessageLength) {
- if (c == ':') {
- sscanf(masterMessageLengthStr.CString(), "%u" , &bytesRemainingInMasterServerMessage_);
- readingMasterMessageLength = false;
- LOGINFO("Message is " + String(bytesRemainingInMasterServerMessage_) + " long");
- }
- else {
- masterMessageLengthStr += c;
- }
- }
- else {
- // Are we reading in the string?
- masterMessageStr += c;
- bytesRemainingInMasterServerMessage_--;
- // Did we hit the end of the string?
- if (bytesRemainingInMasterServerMessage_ == 0) {
- HandleMasterServerMessage(masterMessageStr);
- readingMasterMessageLength = true;
- masterMessageLengthStr = "";
- masterMessageStr = "";
- }
- }
- }
- masterTCPConnection_->EndReceive(buf);
- }
- }
- void MasterServerClient::ConnectToMasterUpdate(float dt)
- {
- if (connectToMasterState_ == MASTER_NOT_CONNECTED ||
- connectToMasterState_ == MASTER_CONNECTION_FAILED)
- {
- return;
- }
- if (connectToMasterState_ == MASTER_CONNECTING_UDP)
- {
- if (udpConnectionSecondsRemaining_ <= 0)
- {
- connectToMasterState_ = MASTER_CONNECTION_FAILED;
- // TODO - emit error event
- return;
- }
- if (udpSecondsTillRetry_ <= 0)
- {
- String msg = "{ \"cmd\": \"registerUDPPort\", \"id\": \"" + masterServerConnectionId_ + "\"}";
- masterUDPConnection_->Send(msg.CString(), msg.Length());
- udpSecondsTillRetry_ = 0.5;
- }
- else
- {
- udpSecondsTillRetry_ -= dt;
- udpConnectionSecondsRemaining_ -= dt;
- }
- }
- }
- void MasterServerClient::HandleBeginFrame(StringHash eventType, VariantMap& eventData)
- {
- using namespace BeginFrame;
- Update(eventData[P_TIMESTEP].GetFloat());
- }
- void MasterServerClient::SetConnectToMasterState(ConnectToMasterState state)
- {
- Atomic::Network* network = GetSubsystem<Network>();
- kNet::Network* kNetNetwork = network->GetKnetNetwork();
- if (connectToMasterState_ == MASTER_NOT_CONNECTED &&
- state == MASTER_CONNECTING_TCP)
- {
- masterTCPConnection_ = kNetNetwork->ConnectSocket(masterServerInfo_.address.CString(),
- masterServerInfo_.port, kNet::SocketOverTCP);
- if (!masterTCPConnection_)
- {
- SetConnectToMasterState(MASTER_CONNECTION_FAILED);
- }
- else
- {
- SendMessageToMasterServer("{ \"cmd\": \"connectRequest\" }");
- }
- }
- else if (connectToMasterState_ == MASTER_CONNECTING_TCP &&
- state == MASTER_CONNECTING_UDP)
- {
- Atomic::Network* network = GetSubsystem<Network>();
- kNet::Network* kNetNetwork = network->GetKnetNetwork();
- kNet::NetworkServer* server = kNetNetwork->GetServer().ptr();
- kNet::EndPoint masterEndPoint;
- sscanf(masterServerInfo_.address.CString(), "%hu.%hu.%hu.%hu",
- (unsigned short *) &masterEndPoint.ip[0],
- (unsigned short *) &masterEndPoint.ip[1],
- (unsigned short *) &masterEndPoint.ip[2],
- (unsigned short *) &masterEndPoint.ip[3]);
- masterEndPoint.port = masterServerInfo_.port;
- if (server)
- {
- std::vector < kNet::Socket * > listenSockets = kNetNetwork->GetServer()->ListenSockets();
- kNet::Socket *listenSocket = listenSockets[0];
- // Create a UDP and a TCP connection to the master server
- // UDP connection re-uses the same udp port we are listening on for the sever
- masterUDPConnection_ = new kNet::Socket(listenSocket->GetSocketHandle(),
- listenSocket->LocalEndPoint(),
- listenSocket->LocalAddress(), masterEndPoint, "",
- kNet::SocketOverUDP, kNet::ServerClientSocket, 1400);
- }
- else
- {
- masterUDPConnection_ = kNetNetwork->CreateUnconnectedUDPSocket(masterServerInfo_.address.CString(),
- masterServerInfo_.port);
- }
- }
- if (state == MASTER_CONNECTION_FAILED)
- {
- LOGERROR("Could not connect to master server");
- SendEvent(E_MASTERCONNECTIONFAILED);
- }
- if (state == MASTER_CONNECTED)
- {
- SendEvent(E_MASTERCONNECTIONREADY);
- }
- connectToMasterState_ = state;
- }
- void MasterServerClient::SetConnectToGameServerState(ClientConnectToGameServerState state)
- {
- if (clientConnectToGameServerState_ == GAME_NOT_CONNECTED &&
- state == GAME_CONNECTING_INTERNAL_IP)
- {
- kNet::EndPoint serverEndPoint;
- sscanf(remoteGameServerInfo_.internalAddress.CString(), "%hu.%hu.%hu.%hu",
- (unsigned short *) &serverEndPoint.ip[0],
- (unsigned short *) &serverEndPoint.ip[1],
- (unsigned short *) &serverEndPoint.ip[2],
- (unsigned short *) &serverEndPoint.ip[3]);
- serverEndPoint.port = remoteGameServerInfo_.internalPort;
- clientToServerSocket_ = new kNet::Socket(masterUDPConnection_->GetSocketHandle(),
- masterUDPConnection_->LocalEndPoint(),
- masterUDPConnection_->LocalAddress(), serverEndPoint, "",
- kNet::SocketOverUDP, kNet::ClientConnectionLessSocket, 1400);
- Atomic::Network* network = GetSubsystem<Network>();
- network->ConnectWithExistingSocket(clientToServerSocket_, remoteGameServerInfo_.clientScene);
- connectToGameServerSecondsRemaining_ = 5.0f;
- LOGINFO("Connecting to Game Server on Internal IP: " +
- remoteGameServerInfo_.internalAddress + ":" +
- String(remoteGameServerInfo_.internalPort));
- }
- else if (clientConnectToGameServerState_ == GAME_CONNECTING_INTERNAL_IP &&
- state == GAME_CONNECTING_EXTERNAL_IP)
- {
- // Ask the master server to tell the game server
- // we want to connect to it.
- String msg = String("{") +
- String("\"cmd\":") + String("\"requestIntroduction\",") +
- String("\"id\":\"") + masterServerConnectionId_ + String("\", ") +
- String("\"serverId\":\"") + remoteGameServerInfo_.serverId + String("\"") +
- String("}");
- SendMessageToMasterServer(msg);
- kNet::EndPoint serverEndPoint;
- sscanf(remoteGameServerInfo_.externalAddress.CString(), "%hu.%hu.%hu.%hu",
- (unsigned short *) &serverEndPoint.ip[0],
- (unsigned short *) &serverEndPoint.ip[1],
- (unsigned short *) &serverEndPoint.ip[2],
- (unsigned short *) &serverEndPoint.ip[3]);
- serverEndPoint.port = remoteGameServerInfo_.externalPort;
- clientToServerSocket_ = new kNet::Socket(masterUDPConnection_->GetSocketHandle(),
- masterUDPConnection_->LocalEndPoint(),
- masterUDPConnection_->LocalAddress(), serverEndPoint, "",
- kNet::SocketOverUDP, kNet::ClientConnectionLessSocket, 1400);
- Atomic::Network* network = GetSubsystem<Network>();
- network->ConnectWithExistingSocket(clientToServerSocket_, remoteGameServerInfo_.clientScene);
- connectToGameServerSecondsRemaining_ = 5.0f;
- LOGINFO("Connecting to Game Server on External IP: " +
- remoteGameServerInfo_.externalAddress + ":" +
- String(remoteGameServerInfo_.externalPort));
- }
- if (state == GAME_CONNECTION_FAILED)
- {
- SendEvent(E_CONNECTFAILED);
- }
- clientConnectToGameServerState_ = state;
- }
- void MasterServerClient::ConnectToGameServerUpdate(float dt)
- {
- if (clientConnectToGameServerState_ == GAME_NOT_CONNECTED ||
- clientConnectToGameServerState_ == GAME_CONNECTED ||
- clientConnectToGameServerState_ == GAME_CONNECTION_FAILED)
- {
- return;
- }
- Atomic::Network* network = GetSubsystem<Network>();
- // If we are connected then set the final state
- if (network->GetServerConnection() && network->GetServerConnection()->IsConnected())
- {
- if (clientConnectToGameServerState_ == GAME_CONNECTING_INTERNAL_IP)
- {
- LOGINFO("Successfully connected using internal IP");
- }
- else if (clientConnectToGameServerState_ == GAME_CONNECTING_EXTERNAL_IP)
- {
- LOGINFO("Successfully connected using external IP");
- }
- SetConnectToGameServerState(GAME_CONNECTED);
- return;
- }
- if (connectToGameServerSecondsRemaining_ <= 0)
- {
- if (clientConnectToGameServerState_ == GAME_CONNECTING_INTERNAL_IP)
- {
- LOGINFO("Unable to connect via internal IP, trying external IP");
- SetConnectToGameServerState(GAME_CONNECTING_EXTERNAL_IP);
- }
- else
- {
- SetConnectToGameServerState(GAME_CONNECTION_FAILED);
- }
- return;
- }
- connectToGameServerSecondsRemaining_ -= dt;
- }
- void MasterServerClient::HandleMasterServerMessage(const String &msg)
- {
- LOGINFO("Got master server message: " + msg);
- rapidjson::Document document;
- if (document.Parse<0>(msg.CString()).HasParseError())
- {
- LOGERROR("Could not parse JSON data from string");
- return;
- }
- String cmd = document["cmd"].GetString();
- bool sendEvent = false;
- if (cmd == "connectTCPSuccess")
- {
- udpSecondsTillRetry_ = 0;
- udpConnectionSecondsRemaining_ = 5.0;
- masterServerConnectionId_ = document["id"].GetString();
- // Now connect with UDP
- SetConnectToMasterState(MASTER_CONNECTING_UDP);
- LOGINFO("TCP Connected");
- }
- else if (cmd == "connectUDPSuccess")
- {
- SetConnectToMasterState(MASTER_CONNECTED);
- // Register server if needed
- if (masterServerInfo_.isRegisteringServer)
- {
- RegisterServerWithMaster(masterServerInfo_.serverName);
- }
- LOGINFO("UDP Connected");
- }
- else if (cmd == "sendPacketToClient")
- {
- String clientIP = document["clientIP"].GetString();
- int clientPort = document["clientPort"].GetInt();
- LOGINFO("Got request to send packet to client at "+clientIP+":"+String(clientPort));
- kNet::EndPoint clientEndPoint;
- sscanf(clientIP.CString(), "%hu.%hu.%hu.%hu",
- (unsigned short *) &clientEndPoint.ip[0],
- (unsigned short *) &clientEndPoint.ip[1],
- (unsigned short *) &clientEndPoint.ip[2],
- (unsigned short *) &clientEndPoint.ip[3]);
- clientEndPoint.port = clientPort;
- // Create a socket that goes out the same port we are listening on to the client.
- // This will be used until the client actually connects.
- kNet::Socket* s = new kNet::Socket(masterUDPConnection_->GetSocketHandle(),
- masterUDPConnection_->LocalEndPoint(),
- masterUDPConnection_->LocalAddress(), clientEndPoint, "",
- kNet::SocketOverUDP, kNet::ServerClientSocket, 1400);
- String clientId = document["clientId"].GetString();
- clientIdToPunchThroughSocketMap_.Insert(MakePair(clientId, s));
- }
- else if (cmd == "serverList")
- {
- sendEvent = true;
- }
- if (sendEvent)
- {
- using namespace NetworkMessage;
- VariantMap& eventData = GetEventDataMap();
- eventData[P_DATA] = msg;
- SendEvent(E_MASTERMESSAGE, eventData);
- }
- }
- bool MasterServerClient::StartServerAndRegisterWithMaster(unsigned short serverPort, const String &masterAddress,
- unsigned short masterPort, const String &serverName)
- {
- Network* network = GetSubsystem<Network>();
- if (!network)
- {
- LOGERROR("MasterServerClient::StartServerAndRegisterWithMaster - Unable to get Network subsystem");
- return false;
- }
- // First start the server
- bool rc = network->StartServer(serverPort);
- if (!rc)
- {
- LOGERROR("MasterServerClient::StartServerAndRegisterWithMaster - Unable to start server");
- return false;
- }
- // Connect to the master server
- ConnectToMasterAndRegister(masterAddress, masterPort, serverName);
- return true;
- }
- }
|