18 #include "precompiled.h"
33 #define DEFAULT_SERVER_NAME L"Unnamed Server"
34 #define DEFAULT_WELCOME_MESSAGE L"Welcome"
51 return "[unknown host]";
53 return "[unauthed host]";
54 return "[" + session->
GetGUID().substr(0, 8) +
"...]";
88 LOGMESSAGE(L
"Net server: rejoining client disconnected before we sent to it");
97 CJoinSyncStartMessage message;
112 m_AutostartPlayers(autostartPlayers),
114 m_ScriptInterface(NULL),
115 m_NextHostID(1), m_Host(NULL), m_Stats(NULL)
143 for (
size_t i = 0; i <
m_Sessions.size(); ++i)
151 enet_host_destroy(
m_Host);
164 addr.host = ENET_HOST_ANY;
171 LOGERROR(L
"Net server: enet_host_create failed");
204 for (
size_t i = 0; i <
m_Sessions.size(); ++i)
260 std::vector<std::pair<int, CStr> > newAssignPlayer;
261 std::vector<bool> newStartGame;
262 std::vector<std::string> newGameAttributes;
263 std::vector<u32> newTurnLength;
277 for (
size_t i = 0; i < newAssignPlayer.size(); ++i)
278 AssignPlayer(newAssignPlayer[i].first, newAssignPlayer[i].second);
280 if (!newGameAttributes.empty())
283 if (!newTurnLength.empty())
287 if (!newStartGame.empty())
291 for (
size_t i = 0; i <
m_Sessions.size(); ++i)
300 LOGERROR(L
"CNetServerWorker: enet_host_service failed (%d)", status);
315 case ENET_EVENT_TYPE_CONNECT:
318 char hostname[256] =
"(error)";
319 enet_address_get_host_ip(&event.peer->address, hostname,
ARRAY_SIZE(hostname));
320 LOGMESSAGE(L
"Net server: Received connection from %hs:%u", hostname, (
unsigned int)event.peer->address.port);
330 ENSURE(event.peer->data == NULL);
331 event.peer->data = session;
338 case ENET_EVENT_TYPE_DISCONNECT:
354 event.peer->data = NULL;
360 case ENET_EVENT_TYPE_RECEIVE:
380 enet_packet_destroy(event.packet);
385 case ENET_EVENT_TYPE_NONE:
401 CFileTransferRequestMessage* reqMessage = (CFileTransferRequestMessage*)message;
413 bool ok = session->
Update(message->
GetType(), (
void*)message);
420 void* context = session;
450 CSrvHandshakeMessage handshake;
465 CPlayerAssignmentMessage assignMessage;
484 std::set<i32> usedIDs;
486 if (it->second.m_Enabled)
487 usedIDs.insert(it->second.m_PlayerID);
493 bool foundPlayerID =
false;
498 if (!it->second.m_Enabled && it->first == guid && usedIDs.find(it->second.m_PlayerID) == usedIDs.end())
500 playerID = it->second.m_PlayerID;
501 foundPlayerID =
true;
512 if (!it->second.m_Enabled && it->second.m_Name == name && usedIDs.find(it->second.m_PlayerID) == usedIDs.end())
514 playerID = it->second.m_PlayerID;
515 foundPlayerID =
true;
525 for (playerID = 1; usedIDs.find(playerID) != usedIDs.end(); ++playerID)
554 if (it->second.m_PlayerID == playerID)
555 it->second.m_PlayerID = -1;
569 if (!it->second.m_Enabled)
572 CPlayerAssignmentMessage::S_m_Hosts h;
573 h.m_GUID = it->first;
574 h.m_Name = it->second.m_Name;
575 h.m_PlayerID = it->second.m_PlayerID;
576 message.m_Hosts.push_back(h);
582 CPlayerAssignmentMessage message;
605 CCliHandshakeMessage* message = (CCliHandshakeMessage*)event->
GetParamRef();
612 CSrvHandshakeResponseMessage handshakeResponse;
615 handshakeResponse.m_Flags = 0;
628 CAuthenticateMessage* message = (CAuthenticateMessage*)event->
GetParamRef();
632 bool isRejoining =
false;
642 if (!it->second.m_Enabled && it->second.m_Name == username)
652 LOGMESSAGE(L
"Refused connection after game start from not-previously-known user \"%ls\"", username.c_str());
663 session->
SetGUID(message->m_GUID);
666 CAuthenticateResultMessage authenticateResult;
668 authenticateResult.m_HostID = newHostID;
669 authenticateResult.m_Message = L
"Logged in";
718 CSyncCheckMessage* syncMessage =
static_cast<CSyncCheckMessage*
> (message);
723 CEndCommandBatchMessage* endMessage =
static_cast<CEndCommandBatchMessage*
> (message);
737 CChatMessage* message = (CChatMessage*)event->
GetParamRef();
739 message->m_GUID = session->
GetGUID();
779 CLoadedGameMessage* message = (CLoadedGameMessage*)event->
GetParamRef();
781 u32 turn = message->m_CurrentTurn;
786 for (
size_t i = turn + 1; i < std::max(readyTurn+1, (
u32)server.
m_SavedCommands.size()); ++i)
794 CEndCommandBatchMessage endMessage;
795 endMessage.m_Turn = i;
805 CLoadedGameMessage loaded;
806 loaded.m_CurrentTurn = readyTurn;
826 for (
size_t i = 0; i <
m_Sessions.size(); ++i)
832 CLoadedGameMessage loaded;
833 loaded.m_CurrentTurn = 0;
843 for (
size_t i = 0; i <
m_Sessions.size(); ++i)
852 CGameStartMessage gameStart;
870 const size_t MAX_LENGTH = 32;
872 CStrW name = original;
873 name.Replace(L
"[", L
"{");
874 name.Replace(L
"]", L
"}");
877 if (name.length() > MAX_LENGTH)
878 name = name.Left(MAX_LENGTH);
892 CStrW name = original;
899 for (
size_t i = 0; i <
m_Sessions.size(); ++i)
911 name = original + L
" (" + CStrW::FromUInt(
id++) + L
")";
NONCOPYABLE(CNetFileReceiveTask_ServerRejoin)
#define PS_PROTOCOL_VERSION
ScriptInterface * m_ScriptInterface
Internal script context for (de)serializing script messages, and for storing game attributes...
void StartGame()
Call from the GUI to asynchronously notify all clients that they should start loading the game...
void UninitialiseClient(int client)
Inform the turn manager that a previously-initialised client has left the game and will no longer be ...
static bool OnClientHandshake(void *context, CFsmEvent *event)
void OnUserLeave(CNetServerSession *session)
static void * RunThread(void *data)
void LatchHostState(const ENetHost *host)
std::vector< std::vector< CSimulationMessage > > m_SavedCommands
A copy of all simulation commands received so far, indexed by turn number, to simplify support for re...
CNetFileTransferer & GetFileTransferer()
static bool OnJoinSyncingLoadedGame(void *context, CFsmEvent *event)
std::string m_JoinSyncFile
The latest copy of the simulation state, received from an existing client when a new client has asked...
Represents a signal in the state machine that a change has occurred.
void CheckGameLoadStatus(CNetServerSession *changedSession)
bool SetupConnection()
Begin listening for network connections.
void HandleMessageReceive(const CNetMessage *message, CNetServerSession *session)
Async task for receiving the initial game state to be forwarded to another client that is rejoining a...
virtual bool SendMessage(const CNetMessage *message)
Send a message to the client.
bool SetupConnection()
Begin listening for network connections.
void StartGame()
Call from the GUI to notify all clients that they should start loading the game.
Locks a CMutex over this object's lifetime.
CNetServerWorker & m_Server
void AddPlayer(const CStr &guid, const CStrW &name)
void UpdateGameAttributes(const CScriptValRooted &attrs)
Call from the GUI to update the game setup attributes.
static CStr DebugName(CNetServerSession *session)
CNetServerWorker & GetServer()
const jsval & get() const
Returns the current value.
static bool OnChat(void *context, CFsmEvent *event)
static bool OnInGame(void *context, CFsmEvent *event)
CNetServer * g_NetServer
Global network server for the standard game.
A trivial wrapper around a jsval.
i32 m_PlayerID
The player that the given host controls, or -1 if none (observer)
Trim all white space from the end of the string.
void Disconnect(u32 reason)
Sends a disconnection notification to the client, and sends a NMT_CONNECTION_LOST message to the sess...
void SetUserName(const CStrW &name)
void NotifyFinishedClientUpdate(int client, u32 turn, const std::string &hash)
CNetServerWorker(int autostartPlayers)
static CStrW SanitisePlayerName(const CStrW &original)
Make a player name 'nicer' by limiting the length and removing forbidden characters etc...
struct _ENetPeer ENetPeer
std::string StringifyJSON(jsval obj, bool indent=true)
Stringify to a JSON string, UTF-8 encoded.
u32 GetSavedTurnLength(u32 turn)
Returns the turn length that was used for the given turn.
CScriptValRooted ParseJSON(const std::string &string_utf8)
Parse a UTF-8-encoded JSON string.
static bool SendMessage(const CNetMessage *message, ENetPeer *peer, const char *peerName)
Transmit a message to the given peer.
void SetNextState(unsigned int nextState)
void StartTask(const shared_ptr< CNetFileReceiveTask > &task)
Registers a file-receiving task.
LIB_API void debug_SetThreadName(const char *name)
inform the debugger of the current thread's name.
std::vector< std::string > m_GameAttributesQueue
CNetServer(int autostartPlayers=-1)
Construct a new network server.
void StartResponse(u32 requestID, const std::string &data)
Registers data to be sent in response to a request.
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
void SetTurnLength(u32 msecs)
Set the turn length to a fixed value.
Status HandleMessageReceive(const CNetMessage *message)
Should be called when a message is received from the network.
#define DEFAULT_SERVER_NAME
int pthread_create(pthread_t *thread_id, const void *attr, void *(*func)(void *), void *arg)
void AssignPlayer(int playerID, const CStr &guid)
Call from the GUI to update the player assignments.
void SetTurnLength(u32 msecs)
void AssignPlayer(int playerID, const CStr &guid)
Call from the GUI to update the player assignments.
std::vector< std::pair< int, CStr > > m_AssignPlayerQueue
CScriptValRooted m_GameAttributes
Asynchronous file-receiving task.
CStrW DeduplicatePlayerName(const CStrW &original)
Make a player name unique, if it matches any existing session's name.
void InitialiseClient(int client, u32 turn)
Inform the turn manager of a new client who will be sending commands.
Special message type for updated to game startup settings.
void UpdateGameAttributes(const CScriptVal &attrs, ScriptInterface &scriptInterface)
Call from the GUI to update the game setup attributes.
void SetupSession(CNetServerSession *session)
#define SAFE_DELETE(p)
delete memory ensuing from new and set the pointer to zero (thus making double-frees safe / a no-op) ...
static const int HOST_SERVICE_TIMEOUT
enet_host_service timeout (msecs).
Network server interface.
void ConstructPlayerAssignmentMessage(CPlayerAssignmentMessage &message)
#define DEFAULT_WELCOME_MESSAGE
ENet connection statistics profiler table.
i64 Status
Error handling system.
std::vector< bool > m_StartGameQueue
static bool IsInitialised()
bool Update(unsigned int eventType, void *pEventData)
std::vector< u32 > m_TurnLengthQueue
std::vector< CNetServerSession * > m_Sessions
NetMessageType GetType() const
Retrieves the message type.
The base class for all network messages exchanged within the game.
void OnUserJoin(CNetServerSession *session)
void NotifyFinishedClientCommands(int client, u32 turn)
const CStrW & GetUserName() const
CNetServerWorker * m_Worker
friend class CNetFileReceiveTask_ServerRejoin
bool m_Enabled
Whether the player is currently connected and active.
unsigned int GetCurrState(void) const
bool HandleConnect(CNetServerSession *session)
const CStr & GetGUID() const
void SetTurnLength(u32 msecs)
Set the turn length to a fixed value.
CFsmTransition * AddTransition(unsigned int state, unsigned int eventType, unsigned int nextState)
virtual size_t GetSerializedLength() const
Retrieves the size in bytes of the serialized message.
static bool OnAuthenticate(void *context, CFsmEvent *event)
CNetFileReceiveTask_ServerRejoin(CNetServerWorker &server, u32 hostID)
Network client/server sessions.
virtual void OnComplete()
Called when m_Buffer contains the full received data.
bool Broadcast(const CNetMessage *message)
Send a message to all clients who have completed the full connection process (i.e.
static bool OnLoadedGame(void *context, CFsmEvent *event)
bool SendMessage(ENetPeer *peer, const CNetMessage *message)
Send a message to the given network peer.
Abstraction around a SpiderMonkey JSContext.
void SendPlayerAssignments()
int pthread_join(pthread_t thread, void **value_ptr)
unsigned int GetType(void) const
ScriptInterface & GetScriptInterface()
Get the script context used for game attributes.
void SetFirstState(unsigned int firstState)
u32 GetReadyTurn()
Returns the latest turn for which all clients are ready; they will have already been told to execute ...
CNetServerTurnManager * m_ServerTurnManager
PlayerAssignmentMap m_PlayerAssignments
static shared_ptr< ScriptRuntime > CreateRuntime(int runtimeSize=DEFAULT_RUNTIME_SIZE)
Returns a runtime, which can used to initialise any number of ScriptInterfaces contexts.
static bool OnDisconnect(void *context, CFsmEvent *event)
Network server worker thread.
The server's end of a network session.
static CNetMessage * CreateMessage(const void *pData, size_t dataSize, ScriptInterface &scriptInterface)
Factory method which creates a message object based on the given data.
void RemovePlayer(const CStr &guid)
virtual CStr ToString() const
Returns a string representation for the message.
void SetGUID(const CStr &guid)
The server-side counterpart to CNetClientTurnManager.
static const int CHANNEL_COUNT
#define PS_PROTOCOL_MAGIC
Special message type for simulation commands.