Ticket #3241: t3241_kick_v6.6.2.patch

File t3241_kick_v6.6.2.patch, 27.5 KB (added by elexis, 8 years ago)
  • binaries/data/mods/public/gui/common/network.js

     
     1/**
     2 * Get a human readable version of the given disconnect reason.
     3 *
     4 * @param reason {number}
     5 * @returns {string}
     6 */
    17function getDisconnectReason(id)
    28{
    39    // Must be kept in sync with source/network/NetHost.h
    410    switch (id)
    511    {
    612    case 0: return translate("Unknown reason");
    713    case 1: return translate("Unexpected shutdown");
    814    case 2: return translate("Incorrect network protocol version");
    915    case 3: return translate("Game is loading, please try later");
    1016    case 4: return translate("Game has already started, no observers allowed");
     17    case 5: return translate("You have been kicked from the match");
     18    case 6: return translate("You have been banned from the match");
    1119    default: return sprintf(translate("\\[Invalid value %(id)s]"), { "id": id });
    1220    }
    1321}
    1422
     23/**
     24 * Show the disconnect reason in a message box.
     25 *
     26 * @param {number} reason
     27 */
    1528function reportDisconnect(reason)
    1629{
    17     var reasontext = getDisconnectReason(reason);
     30    // Translation: States the reason why the client disconnected from the server.
     31    var reasonText = sprintf(translate("Reason: %(reason)s."), { "reason": getDisconnectReason(reason) })
     32    messageBox(400, 200, translate("Lost connection to the server.") + "\n\n" + reasonText, translate("Disconnected"), 2);
     33}
     34
     35/**
     36 * Get usernames sorted by player slot, observers last.
     37 * Requires g_PlayerAssignments.
     38 *
     39 * @returns {string[]}
     40 */
     41function getUsernameList()
     42{
     43    return Object.keys(g_PlayerAssignments).sort((guidA, guidB) => {
     44
     45        var playerIdA = g_PlayerAssignments[guidA].player;
     46        var playerIdB = g_PlayerAssignments[guidB].player;
     47
     48        // Sort observers last
     49        if (playerIdA == -1) return +1;
     50        if (playerIdB == -1) return -1;
     51
     52        // Sort players
     53        return playerIdA - playerIdB;
     54
     55    }).map(guid => g_PlayerAssignments[guid].name);
     56}
    1857
    19     messageBox(400, 200,
    20         translate("Lost connection to the server.") + "\n\n" + sprintf(translate("Reason: %(reason)s."), { reason: reasontext }),
    21         translate("Disconnected"), 2);
     58/**
     59 * Execute a command locally. Requires addChatMessage.
     60 *
     61 * @param {string} input
     62 * @returns {Boolean} whether a command was executed
     63 */
     64function executeNetworkCommand(input)
     65{
     66    if (input.indexOf("/") != 0)
     67        return false;
     68
     69    var command = input.split(" ", 1)[0];
     70    var argument = input.substr(command.length + 1);
     71
     72    switch (command)
     73    {
     74    case "/list":
     75        addChatMessage({ "type": "clientlist", "guid": "local" });
     76        return true;
     77
     78    case "/kick":
     79        if (!Engine.KickPlayer(argument, false))
     80            addChatMessage({ "type": "system", "text": sprintf(translate("Could not kick user %(name)s."), { "name": argument }) });
     81        return true;
     82
     83    case "/ban":
     84        if (!Engine.KickPlayer(argument, true))
     85            addChatMessage({ "type": "system", "text": sprintf(translate("Could not ban user %(name)s."), { "name": argument }) });
     86        return true;
     87    }
     88    return false;
    2289}
  • binaries/data/mods/public/gui/gamesetup/gamesetup.js

    function handleNetMessage(message)  
    506506
    507507    case "chat":
    508508        addChatMessage({ "type": "message", "guid": message.guid, "text": message.text });
    509509        break;
    510510
     511    case "kicked":
     512        addChatMessage({ "type": "system", "text": "== " + sprintf(translate("%(username)s has been kicked"), { "username": message.username })});
     513        break;
     514
     515    case "banned":
     516        addChatMessage({ "type": "system", "text": "== " + sprintf(translate("%(username)s has been banned"), { "username": message.username })});
     517        break;
     518
    511519    // Singular client to host message
    512520    case "ready":
    513521        g_ReadyChanged -= 1;
    514522        if (g_ReadyChanged < 1 && g_PlayerAssignments[message.guid].player != -1)
    515523            addChatMessage({ "type": "ready", "guid": message.guid, "ready": +message.status == 1 });
    function submitChatInput()  
    17741782    var input = Engine.GetGUIObjectByName("chatInput");
    17751783    var text = input.caption;
    17761784    if (!text.length)
    17771785        return;
    17781786
    1779     Engine.SendNetworkChat(text);
    17801787    input.caption = "";
     1788
     1789    if (executeNetworkCommand(text))
     1790        return;
     1791
     1792    Engine.SendNetworkChat(text);
    17811793}
    17821794
    17831795function addChatMessage(msg)
    17841796{
    17851797    var username = "";
    function addChatMessage(msg)  
    18101822    case "disconnect":
    18111823        var formattedUsername = '[color="'+ color +'"]' + username + '[/color]';
    18121824        formatted = '[font="sans-bold-13"] ' + sprintf(translate("== %(message)s"), { "message": sprintf(translate("%(username)s has left"), { "username": formattedUsername }) }) + '[/font]';
    18131825        break;
    18141826
     1827    case "clientlist":
     1828        formatted = sprintf(translate("Users: %(users)s"), { "users": getUsernameList().join(",") });
     1829        break;
     1830
     1831    case "system":
     1832        formatted = '[font="sans-bold-13"] ' + msg.text + '[/font]';
     1833        break;
     1834
    18151835    case "message":
    18161836        var formattedUsername = '[color="'+ color +'"]' + username + '[/color]';
    18171837        var formattedUsernamePrefix = '[font="sans-bold-13"]' + sprintf(translate("<%(username)s>"), { "username": formattedUsername }) + '[/font]';
    18181838        formatted = sprintf(translate("%(username)s %(message)s"), { "username": formattedUsernamePrefix, "message": message });
    18191839        break;
  • binaries/data/mods/public/gui/session/messages.js

    function handleNetMessage(message)  
    267267            obj.caption = translate("Connection to the server has been authenticated.");
    268268            obj.hidden = false;
    269269            break;
    270270        case "disconnected":
    271271            g_Disconnected = true;
    272             obj.caption = translate("Connection to the server has been lost.") + "\n\n" + translate("The game has ended.");
     272            // Translation: States the reason why the client disconnected from the server.
     273            let reason = sprintf(translate("Reason: %(reason)s."), { "reason": getDisconnectReason(message.reason) });
     274            obj.caption = translate("Connection to the server has been lost.") + "\n" + reason + "\n" + translate("The game has ended.");
    273275            obj.hidden = false;
    274276            break;
    275277        default:
    276278            error("Unrecognised netstatus type '" + message.status + "'");
    277279            break;
    function handleNetMessage(message)  
    323325
    324326    case "rejoined":
    325327        addChatMessage({ "type": "rejoined", "guid": message.guid });
    326328        break;
    327329
     330    case "kicked":
     331        addChatMessage({ "type": "system", "text": sprintf(translate("%(username)s has been kicked"), { "username": message.username })});
     332        break;
     333
     334    case "banned":
     335        addChatMessage({ "type": "system", "text": sprintf(translate("%(username)s has been banned"), { "username": message.username })});
     336        break;
     337
    328338    // To prevent errors, ignore these message types that occur during autostart
    329339    case "gamesetup":
    330340    case "start":
    331341        break;
    332342
    function submitChatInput()  
    357367    toggleChatWindow();
    358368
    359369    if (!text.length)
    360370        return;
    361371
     372    if (executeNetworkCommand(text))
     373        return;
     374
    362375    if (executeCheat(text))
    363376        return;
    364377
    365378    // Observers should only be able to chat with everyone.
    366379    if (g_IsObserver && text.indexOf("/") == 0 && text.indexOf("/me ") != 0)
    function addChatMessage(msg)  
    418431        formatted = sprintf(translate("%(player)s has left the game."), { "player": "[color=\"" + playerColor + "\"]" + username + "[/color]" });
    419432        break;
    420433    case "rejoined":
    421434        formatted = sprintf(translate("%(player)s has rejoined the game."), { "player": "[color=\"" + playerColor + "\"]" + username + "[/color]" });
    422435        break;
     436    case "clientlist":
     437        formatted = sprintf(translate("Users: %(users)s"), { "users": getUsernameList().join(",") });
     438        break;
     439    case "system":
     440        formatted = msg.text;
     441        break;
    423442    case "defeat":
    424443        // In singleplayer, the local player is "You". "You has" is incorrect.
    425444        if (!g_IsNetworked && msg.player == Engine.GetPlayerID())
    426445            formatted = translate("You have been defeated.");
    427446        else
  • binaries/data/mods/public/gui/session/session.xml

     
    66<script file="gui/common/functions_civinfo.js"/>
    77<script file="gui/common/functions_global_object.js"/>
    88<script file="gui/common/functions_utility.js"/>
    99<script file="gui/common/l10n.js"/>
    1010<script file="gui/common/music.js"/>
     11<script file="gui/common/network.js"/>
    1112<script file="gui/common/settings.js"/>
    1213<script file="gui/common/timer.js"/>
    1314<script file="gui/common/tooltips.js"/>
    1415<!-- load all scripts in this directory -->
    1516<script directory="gui/session/"/>
  • source/gui/scripting/ScriptFunctions.cpp

    void DisconnectNetworkGame(ScriptInterfa  
    351351    SAFE_DELETE(g_NetServer);
    352352    SAFE_DELETE(g_NetClient);
    353353    SAFE_DELETE(g_Game);
    354354}
    355355
     356bool KickPlayer(ScriptInterface::CxPrivate* UNUSED(pCxPrivate), CStrW playerName, bool ban)
     357{
     358    if (!g_NetServer)
     359        return false;
     360
     361    return g_NetServer->KickPlayer(playerName, ban);
     362}
     363
    356364JS::Value PollNetworkClient(ScriptInterface::CxPrivate* pCxPrivate)
    357365{
    358366    if (!g_NetClient)
    359367        return JS::UndefinedValue();
    360368
    void GuiScriptingInit(ScriptInterface& s  
    961969    scriptInterface.RegisterFunction<void, JS::HandleValue, int, &StartGame>("StartGame");
    962970    scriptInterface.RegisterFunction<void, &Script_EndGame>("EndGame");
    963971    scriptInterface.RegisterFunction<void, std::wstring, &StartNetworkHost>("StartNetworkHost");
    964972    scriptInterface.RegisterFunction<void, std::wstring, std::string, &StartNetworkJoin>("StartNetworkJoin");
    965973    scriptInterface.RegisterFunction<void, &DisconnectNetworkGame>("DisconnectNetworkGame");
     974    scriptInterface.RegisterFunction<bool, CStrW, bool, &KickPlayer>("KickPlayer");
    966975    scriptInterface.RegisterFunction<JS::Value, &PollNetworkClient>("PollNetworkClient");
    967976    scriptInterface.RegisterFunction<void, JS::HandleValue, &SetNetworkGameAttributes>("SetNetworkGameAttributes");
    968977    scriptInterface.RegisterFunction<void, int, std::string, &AssignNetworkPlayer>("AssignNetworkPlayer");
    969978    scriptInterface.RegisterFunction<void, std::string, int, &SetNetworkPlayerStatus>("SetNetworkPlayerStatus");
    970979    scriptInterface.RegisterFunction<void, &ClearAllPlayerReady>("ClearAllPlayerReady");
  • source/network/NetClient.cpp

    CNetClient::CNetClient(CGame* game) :  
    9191
    9292    AddTransition(NCS_PREGAME, (uint)NMT_CHAT, NCS_PREGAME, (void*)&OnChat, context);
    9393    AddTransition(NCS_PREGAME, (uint)NMT_READY, NCS_PREGAME, (void*)&OnReady, context);
    9494    AddTransition(NCS_PREGAME, (uint)NMT_GAME_SETUP, NCS_PREGAME, (void*)&OnGameSetup, context);
    9595    AddTransition(NCS_PREGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_PREGAME, (void*)&OnPlayerAssignment, context);
     96    AddTransition(NCS_PREGAME, (uint)NMT_KICKED, NCS_PREGAME, (void*)&OnKicked, context);
    9697    AddTransition(NCS_PREGAME, (uint)NMT_GAME_START, NCS_LOADING, (void*)&OnGameStart, context);
    9798    AddTransition(NCS_PREGAME, (uint)NMT_JOIN_SYNC_START, NCS_JOIN_SYNCING, (void*)&OnJoinSyncStart, context);
    9899
    99100    AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CHAT, NCS_JOIN_SYNCING, (void*)&OnChat, context);
    100101    AddTransition(NCS_JOIN_SYNCING, (uint)NMT_GAME_SETUP, NCS_JOIN_SYNCING, (void*)&OnGameSetup, context);
    CNetClient::CNetClient(CGame* game) :  
    108109    AddTransition(NCS_LOADING, (uint)NMT_GAME_SETUP, NCS_LOADING, (void*)&OnGameSetup, context);
    109110    AddTransition(NCS_LOADING, (uint)NMT_PLAYER_ASSIGNMENT, NCS_LOADING, (void*)&OnPlayerAssignment, context);
    110111    AddTransition(NCS_LOADING, (uint)NMT_LOADED_GAME, NCS_INGAME, (void*)&OnLoadedGame, context);
    111112
    112113    AddTransition(NCS_INGAME, (uint)NMT_REJOINED, NCS_INGAME, (void*)&OnRejoined, context);
     114    AddTransition(NCS_INGAME, (uint)NMT_KICKED, NCS_INGAME, (void*)&OnKicked, context);
    113115    AddTransition(NCS_INGAME, (uint)NMT_CHAT, NCS_INGAME, (void*)&OnChat, context);
    114116    AddTransition(NCS_INGAME, (uint)NMT_GAME_SETUP, NCS_INGAME, (void*)&OnGameSetup, context);
    115117    AddTransition(NCS_INGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_INGAME, (void*)&OnPlayerAssignment, context);
    116118    AddTransition(NCS_INGAME, (uint)NMT_SIMULATION_COMMAND, NCS_INGAME, (void*)&OnInGame, context);
    117119    AddTransition(NCS_INGAME, (uint)NMT_SYNC_ERROR, NCS_INGAME, (void*)&OnInGame, context);
    bool CNetClient::OnRejoined(void *contex  
    605607    client->PushGuiMessage(msg);
    606608
    607609    return true;
    608610}
    609611
     612bool CNetClient::OnKicked(void *context, CFsmEvent* event)
     613{
     614    ENSURE(event->GetType() == (uint)NMT_KICKED);
     615
     616    CNetClient* client = (CNetClient*)context;
     617    JSContext* cx = client->GetScriptInterface().GetContext();
     618
     619    CKickedMessage* message = (CKickedMessage*)event->GetParamRef();
     620    JS::RootedValue msg(cx);
     621
     622    client->GetScriptInterface().Eval("({})", &msg);
     623    client->GetScriptInterface().SetProperty(msg, "username", message->m_Name);
     624    if (message->m_Ban)
     625        client->GetScriptInterface().SetProperty(msg, "type", std::string("banned"));
     626    else
     627        client->GetScriptInterface().SetProperty(msg, "type", std::string("kicked"));
     628
     629    client->PushGuiMessage(msg);
     630
     631    return true;
     632}
     633
    610634bool CNetClient::OnLoadedGame(void* context, CFsmEvent* event)
    611635{
    612636    ENSURE(event->GetType() == (uint)NMT_LOADED_GAME);
    613637
    614638    CNetClient* client = (CNetClient*)context;
  • source/network/NetClient.h

    private:  
    199199    static bool OnInGame(void* context, CFsmEvent* event);
    200200    static bool OnGameStart(void* context, CFsmEvent* event);
    201201    static bool OnJoinSyncStart(void* context, CFsmEvent* event);
    202202    static bool OnJoinSyncEndCommandBatch(void* context, CFsmEvent* event);
    203203    static bool OnRejoined(void* context, CFsmEvent* event);
     204    static bool OnKicked(void* context, CFsmEvent* event);
    204205    static bool OnLoadedGame(void* context, CFsmEvent* event);
    205206
    206207    /**
    207208     * Take ownership of a session object, and use it for all network communication.
    208209     */
  • source/network/NetHost.h

    enum NetDisconnectReason  
    6161{
    6262    NDR_UNKNOWN = 0,
    6363    NDR_UNEXPECTED_SHUTDOWN,
    6464    NDR_INCORRECT_PROTOCOL_VERSION,
    6565    NDR_SERVER_LOADING,
    66     NDR_SERVER_ALREADY_IN_GAME
     66    NDR_SERVER_ALREADY_IN_GAME,
     67    NDR_KICKED,
     68    NDR_BANNED
    6769};
    6870
    6971class CNetHost
    7072{
    7173public:
  • source/network/NetMessage.cpp

    CNetMessage* CNetMessageFactory::CreateM  
    133133
    134134    case NMT_REJOINED:
    135135        pNewMessage = new CRejoinedMessage;
    136136        break;
    137137
     138    case NMT_KICKED:
     139        pNewMessage = new CKickedMessage;
     140        break;
     141
    138142    case NMT_LOADED_GAME:
    139143        pNewMessage = new CLoadedGameMessage;
    140144        break;
    141145
    142146    case NMT_SERVER_HANDSHAKE:
  • source/network/NetMessages.h

     
    2626#include "ps/CStr.h"
    2727#include "scriptinterface/ScriptVal.h"
    2828
    2929#define PS_PROTOCOL_MAGIC               0x5073013f      // 'P', 's', 0x01, '?'
    3030#define PS_PROTOCOL_MAGIC_RESPONSE      0x50630121      // 'P', 'c', 0x01, '!'
    31 #define PS_PROTOCOL_VERSION             0x01010007      // Arbitrary protocol
     31#define PS_PROTOCOL_VERSION             0x01010008      // Arbitrary protocol
    3232#define PS_DEFAULT_PORT                 0x5073          // 'P', 's'
    3333
    3434// Defines the list of message types. The order of the list must not change.
    3535// The message types having a negative value are used internally and not sent
    3636// over the network. The message types used for network communication have
    enum NetMessageType  
    5656    NMT_FILE_TRANSFER_ACK,
    5757
    5858    NMT_JOIN_SYNC_START,
    5959
    6060    NMT_REJOINED,
     61    NMT_KICKED,
    6162
    6263    NMT_LOADED_GAME,
    6364    NMT_GAME_START,
    6465    NMT_END_COMMAND_BATCH,
    6566    NMT_SYNC_CHECK, // OOS-detection hash checking
    END_NMT_CLASS()  
    159160
    160161START_NMT_CLASS_(Rejoined, NMT_REJOINED)
    161162    NMT_FIELD(CStr8, m_GUID)
    162163END_NMT_CLASS()
    163164
     165START_NMT_CLASS_(Kicked, NMT_KICKED)
     166    NMT_FIELD(CStrW, m_Name)
     167    NMT_FIELD_INT(m_Ban, bool, 1)
     168END_NMT_CLASS()
     169
    164170START_NMT_CLASS_(LoadedGame, NMT_LOADED_GAME)
    165171    NMT_FIELD_INT(m_CurrentTurn, u32, 4)
    166172END_NMT_CLASS()
    167173
    168174START_NMT_CLASS_(GameStart, NMT_GAME_START)
  • source/network/NetServer.cpp

    private:  
    119119
    120120CNetServerWorker::CNetServerWorker(int autostartPlayers) :
    121121    m_AutostartPlayers(autostartPlayers),
    122122    m_Shutdown(false),
    123123    m_ScriptInterface(NULL),
    124     m_NextHostID(1), m_Host(NULL), m_Stats(NULL)
     124    m_NextHostID(1), m_Host(NULL), m_HostGUID(), m_Stats(NULL)
    125125{
    126126    m_State = SERVER_STATE_UNCONNECTED;
    127127
    128128    m_ServerTurnManager = NULL;
    129129
    bool CNetServerWorker::RunStep()  
    472472
    473473    switch (event.type)
    474474    {
    475475    case ENET_EVENT_TYPE_CONNECT:
    476476    {
    477         // Report the client address
    478         char hostname[256] = "(error)";
    479         enet_address_get_host_ip(&event.peer->address, hostname, ARRAY_SIZE(hostname));
    480         LOGMESSAGE("Net server: Received connection from %s:%u", hostname, (unsigned int)event.peer->address.port);
    481 
    482477        // Set up a session object for this peer
    483 
    484478        CNetServerSession* session = new CNetServerSession(*this, event.peer);
    485479
     480        // Report the client address
     481        LOGMESSAGE("Net server: Received connection from %s:%u", session->GetIPAddress().c_str(), (unsigned int)event.peer->address.port);
     482
    486483        m_Sessions.push_back(session);
    487484
    488485        SetupSession(session);
    489486
    490487        ENSURE(event.peer->data == NULL);
    void CNetServerWorker::SetupSession(CNet  
    608605    session->SetFirstState(NSS_HANDSHAKE);
    609606}
    610607
    611608bool CNetServerWorker::HandleConnect(CNetServerSession* session)
    612609{
     610    CNetServerWorker& server = session->GetServer();
     611
     612    // Disconnect banned IPs
     613    if (std::find(server.m_BannedIPs.begin(), server.m_BannedIPs.end(), session->GetIPAddress()) != server.m_BannedIPs.end())
     614    {
     615        session->Disconnect(NDR_BANNED);
     616        return false;
     617    }
     618
     619    // Send handshake challenge
    613620    CSrvHandshakeMessage handshake;
    614621    handshake.m_Magic = PS_PROTOCOL_MAGIC;
    615622    handshake.m_ProtocolVersion = PS_PROTOCOL_VERSION;
    616623    handshake.m_SoftwareVersion = PS_PROTOCOL_VERSION;
    617624    return session->SendMessage(&handshake);
    bool CNetServerWorker::HandleConnect(CNe  
    619626
    620627void CNetServerWorker::OnUserJoin(CNetServerSession* session)
    621628{
    622629    AddPlayer(session->GetGUID(), session->GetUserName());
    623630
     631    // Host is the first to join
     632    if (m_HostGUID.empty())
     633        m_HostGUID = session->GetGUID();
     634
    624635    CGameSetupMessage gameSetupMessage(GetScriptInterface());
    625636    gameSetupMessage.m_Data = m_GameAttributes.get();
    626637    session->SendMessage(&gameSetupMessage);
    627638
    628639    CPlayerAssignmentMessage assignMessage;
    void CNetServerWorker::ClearAllPlayerRea  
    711722        it->second.m_Status = 0;
    712723
    713724    SendPlayerAssignments();
    714725}
    715726
     727bool CNetServerWorker::KickPlayer(const CStrW& playerName, const bool ban)
     728{
     729    // Find the user with that name
     730    std::vector<CNetServerSession*>::iterator it = std::find_if(m_Sessions.begin(), m_Sessions.end(),
     731        [&](CNetServerSession* session) { return session->GetUserName() == playerName; });
     732
     733    // and return if no one or the host has that name
     734    if (it == m_Sessions.end() || (*it)->GetGUID() == m_HostGUID)
     735        return false;
     736
     737    if (ban)
     738    {
     739        // Remember name
     740        if (std::find(m_BannedPlayers.begin(), m_BannedPlayers.end(), playerName) == m_BannedPlayers.end())
     741            m_BannedPlayers.push_back(playerName);
     742
     743        // Remember IP address
     744        CStr ipAddress = GetPlayerIPAddress(playerName);
     745        if (ipAddress != "" && std::find(m_BannedIPs.begin(), m_BannedIPs.end(), ipAddress) == m_BannedIPs.end())
     746            m_BannedIPs.push_back(ipAddress);
     747    }
     748
     749    // Disconnect that user
     750    (*it)->Disconnect(ban ? NDR_BANNED : NDR_KICKED);
     751
     752    // Send message notifying other clients
     753    CKickedMessage kickedMessage;
     754    kickedMessage.m_Name = playerName;
     755    kickedMessage.m_Ban = ban;
     756    Broadcast(&kickedMessage);
     757
     758    return true;
     759}
     760
     761CStr CNetServerWorker::GetPlayerIPAddress(const CStrW& playerName)
     762{
     763    for (CNetServerSession* session : m_Sessions)
     764        if (session->GetUserName() == playerName)
     765            return session->GetIPAddress();
     766    return "";
     767}
     768
    716769void CNetServerWorker::AssignPlayer(int playerID, const CStr& guid)
    717770{
    718771    // Remove anyone who's already assigned to this player
    719772    for (PlayerAssignmentMap::iterator it = m_PlayerAssignments.begin(); it != m_PlayerAssignments.end(); ++it)
    720773    {
    bool CNetServerWorker::OnClientHandshake  
    768821    ENSURE(event->GetType() == (uint)NMT_CLIENT_HANDSHAKE);
    769822
    770823    CNetServerSession* session = (CNetServerSession*)context;
    771824    CNetServerWorker& server = session->GetServer();
    772825
     826    // Check protocol version
    773827    CCliHandshakeMessage* message = (CCliHandshakeMessage*)event->GetParamRef();
    774828    if (message->m_ProtocolVersion != PS_PROTOCOL_VERSION)
    775829    {
    776830        session->Disconnect(NDR_INCORRECT_PROTOCOL_VERSION);
    777831        return false;
    778832    }
    779833
     834    // Send handshake response
    780835    CSrvHandshakeResponseMessage handshakeResponse;
    781836    handshakeResponse.m_UseProtocolVersion = PS_PROTOCOL_VERSION;
    782837    handshakeResponse.m_Message = server.m_WelcomeMessage;
    783838    handshakeResponse.m_Flags = 0;
    784839    session->SendMessage(&handshakeResponse);
    bool CNetServerWorker::OnAuthenticate(vo  
    802857    }
    803858
    804859    CAuthenticateMessage* message = (CAuthenticateMessage*)event->GetParamRef();
    805860    CStrW username = server.DeduplicatePlayerName(SanitisePlayerName(message->m_Name));
    806861
     862    // Disconnect banned usernames
     863    if (std::find(server.m_BannedPlayers.begin(), server.m_BannedPlayers.end(), username) != server.m_BannedPlayers.end())
     864    {
     865        session->Disconnect(NDR_BANNED);
     866        return true;
     867    }
     868
    807869    // Optionally allow observers to join after the game has started
    808870    bool observerLateJoin = false;
    809871    ScriptInterface& scriptInterface = server.GetScriptInterface();
    810872    JSContext* cx = scriptInterface.GetContext();
    811873    JSAutoRequest rq(cx);
    CNetServer::~CNetServer()  
    11661228bool CNetServer::SetupConnection()
    11671229{
    11681230    return m_Worker->SetupConnection();
    11691231}
    11701232
     1233bool CNetServer::KickPlayer(const CStrW& playerName, const bool ban)
     1234{
     1235    CScopeLock lock(m_Worker->m_WorkerMutex);
     1236    return m_Worker->KickPlayer(playerName, ban);
     1237}
     1238
    11711239void CNetServer::AssignPlayer(int playerID, const CStr& guid)
    11721240{
    11731241    CScopeLock lock(m_Worker->m_WorkerMutex);
    11741242    m_Worker->m_AssignPlayerQueue.emplace_back(playerID, guid);
    11751243}
  • source/network/NetServer.h

    public:  
    132132    /**
    133133     * Call from the GUI to set the all player readiness to 0.
    134134     * The changes will be asynchronously propagated to all clients.
    135135     */
    136136    void ClearAllPlayerReady();
    137    
     137
     138    /**
     139     * Disconnects a player from the gamesetup / session.
     140     */
     141    bool KickPlayer(const CStrW& playerName, const bool ban);
     142
    138143    /**
    139144     * Call from the GUI to asynchronously notify all clients that they should start loading the game.
    140145     */
    141146    void StartGame();
    142147
    public:  
    181186     * Send a message to the given network peer.
    182187     */
    183188    bool SendMessage(ENetPeer* peer, const CNetMessage* message);
    184189
    185190    /**
     191     * Disconnected a player from the match / gamesetup and optionally prevents him/her from rejoining.
     192     */
     193    bool KickPlayer(const CStrW& playerName, const bool ban);
     194
     195    /**
    186196     * Send a message to all clients who have completed the full connection process
    187197     * (i.e. are in the pre-game or in-game states).
    188198     */
    189199    bool Broadcast(const CNetMessage* message);
    190200
     201    /**
     202     * Returns the IP address of the given connected player.
     203     */
     204    CStr GetPlayerIPAddress(const CStrW& playerName);
     205
    191206private:
    192207    friend class CNetServer;
    193208    friend class CNetFileReceiveTask_ServerRejoin;
    194209
    195210    CNetServerWorker(int autostartPlayers);
    private:  
    244259    void SetTurnLength(u32 msecs);
    245260
    246261    void AddPlayer(const CStr& guid, const CStrW& name);
    247262    void RemovePlayer(const CStr& guid);
    248263    void SetPlayerReady(const CStr& guid, const int ready);
     264    CStr GetHostGUID();
    249265    void SendPlayerAssignments();
    250266    void ClearAllPlayerReady();
    251267
    252268    void SetupSession(CNetServerSession* session);
    253269    bool HandleConnect(CNetServerSession* session);
    private:  
    297313    NetServerState m_State;
    298314
    299315    CStrW m_ServerName;
    300316    CStrW m_WelcomeMessage;
    301317
     318    std::vector<CStr> m_BannedIPs;
     319    std::vector<CStrW> m_BannedPlayers;
     320
    302321    u32 m_NextHostID;
    303322
    304323    CNetServerTurnManager* m_ServerTurnManager;
    305324
     325    CStr m_HostGUID;
     326
    306327    /**
    307328     * A copy of all simulation commands received so far, indexed by
    308329     * turn number, to simplify support for rejoining etc.
    309330     * TODO: verify this doesn't use too much RAM.
    310331     */
  • source/network/NetSession.cpp

     
    1 /* Copyright (C) 2011 Wildfire Games.
     1/* Copyright (C) 2015 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
    55 * it under the terms of the GNU General Public License as published by
    66 * the Free Software Foundation, either version 2 of the License, or
    void CNetClientSession::Poll()  
    108108        case ENET_EVENT_TYPE_CONNECT:
    109109        {
    110110            ENSURE(event.peer == m_Server);
    111111
    112112            // Report the server address
    113             char hostname[256] = "(error)";
     113            char hostname[256] = "";
    114114            enet_address_get_host_ip(&event.peer->address, hostname, ARRAY_SIZE(hostname));
    115115            LOGMESSAGE("Net client: Connected to %s:%u", hostname, (unsigned int)event.peer->address.port);
    116116
    117117            m_Client.HandleConnect();
    118118
    bool CNetClientSession::SendMessage(cons  
    173173CNetServerSession::CNetServerSession(CNetServerWorker& server, ENetPeer* peer) :
    174174    m_Server(server), m_FileTransferer(this), m_Peer(peer)
    175175{
    176176}
    177177
     178CStr CNetServerSession::GetIPAddress()
     179{
     180    char ipAddress[256] = "";
     181    if (enet_address_get_host_ip(&(m_Peer->address), ipAddress, ARRAY_SIZE(ipAddress)) < 0)
     182    {
     183        LOGERROR("Could not get IP address of a client!");
     184        return "";
     185    }
     186
     187    return CStr(ipAddress);
     188}
     189
    178190void CNetServerSession::Disconnect(u32 reason)
    179191{
    180192    Update((uint)NMT_CONNECTION_LOST, NULL);
    181193
    182194    enet_peer_disconnect(m_Peer, reason);
  • source/network/NetSession.h

     
    1 /* Copyright (C) 2011 Wildfire Games.
     1/* Copyright (C) 2015 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
    55 * it under the terms of the GNU General Public License as published by
    66 * the Free Software Foundation, either version 2 of the License, or
    public:  
    121121
    122122    u32 GetHostID() const { return m_HostID; }
    123123    void SetHostID(u32 id) { m_HostID = id; }
    124124
    125125    /**
     126     * Returns the IP address of the client.
     127     */
     128    CStr GetIPAddress();
     129
     130    /**
    126131     * Sends a disconnection notification to the client,
    127132     * and sends a NMT_CONNECTION_LOST message to the session FSM.
    128133     * The server will receive a disconnection notification after a while.
    129134     * The server will not receive any further messages sent via this session.
    130135     */