Search in sources :

Example 26 with Connection

use of soc.server.genericServer.Connection in project JSettlers2 by jdmonin.

the class SOCServerMessageHandler method processDebugCommand_who.

/**
 * Process unprivileged command {@code *WHO*} to show members of current game,
 * or privileged {@code *WHO* gameName|all|*} to show all connected clients or some other game's members.
 *<P>
 * <B>Locks:</B> Takes/releases {@link SOCGameList#takeMonitorForGame(String) gameList.takeMonitorForGame(gaName)}
 * to call {@link SOCGameListAtServer#getMembers(String)}.
 *
 * @param c  Client sending the *WHO* command
 * @param ga  Game in which the command was sent
 * @param cmdText   Text of *WHO* command
 * @since 1.1.20
 */
private void processDebugCommand_who(final Connection c, final SOCGame ga, final String cmdText) {
    // name of game where c is connected and sent *WHO* command
    final String gaName = ga.getName();
    // name of game to find members; if sendToCli, not equal to gaName
    String gaNameWho = gaName;
    // if true, send member list only to c instead of whole game
    boolean sendToCli = false;
    int i = cmdText.indexOf(' ');
    if (i != -1) {
        // look for a game name or */all
        String gname = cmdText.substring(i + 1).trim();
        if (gname.length() > 0) {
            // Check if using user admins; if not, if using debug user
            final String uname = c.getData();
            boolean isAdmin = srv.isUserDBUserAdmin(uname);
            if (!isAdmin)
                isAdmin = (srv.isDebugUserEnabled() && uname.equals("debug"));
            if (!isAdmin) {
                srv.messageToPlayerKeyed(c, gaName, "reply.must_be_admin.view");
                // "Must be an administrator to view that."
                return;
            }
            sendToCli = true;
            if (gname.equals("*") || gname.toUpperCase(Locale.US).equals("ALL")) {
                // Instead of listing the game's members, list all connected clients.
                // Build list of StringBuilder not String to do as little as possible
                // inside synchronization block.
                final ArrayList<StringBuilder> sbs = new ArrayList<StringBuilder>();
                sbs.add(new StringBuilder(c.getLocalized("reply.who.conn_to_srv")));
                // "Currently connected to server:"
                final Integer nUnnamed = srv.getConnectedClientNames(sbs);
                if (nUnnamed.intValue() != 0) {
                    StringBuilder sb = new StringBuilder("- ");
                    sb.append(c.getLocalized("reply.who.and_unnamed", nUnnamed));
                    // "and {0} unnamed connections"
                    sbs.add(sb);
                }
                for (StringBuilder sbb : sbs) srv.messageToPlayer(c, gaName, sbb.toString());
                // <--- Early return; Not listing a game's members ---
                return;
            }
            if (gameList.isGame(gname)) {
                gaNameWho = gname;
            } else {
                // "Game not found."
                srv.messageToPlayerKeyed(c, gaName, "reply.game.not.found");
                return;
            }
        }
    }
    Vector<Connection> gameMembers = null;
    gameList.takeMonitorForGame(gaNameWho);
    try {
        gameMembers = gameList.getMembers(gaNameWho);
        if (!sendToCli)
            // "This game's members:"
            srv.messageToGameKeyed(ga, false, "reply.game_members.this");
    } catch (Exception e) {
        D.ebugPrintStackTrace(e, "Exception in *WHO* (gameMembers)");
    }
    gameList.releaseMonitorForGame(gaNameWho);
    if (gameMembers == null) {
        // unlikely since empty games are destroyed
        return;
    }
    if (sendToCli)
        // "Members of game {0}:"
        srv.messageToPlayerKeyed(c, gaName, "reply.game_members.of", gaNameWho);
    Enumeration<Connection> membersEnum = gameMembers.elements();
    while (membersEnum.hasMoreElements()) {
        Connection conn = membersEnum.nextElement();
        String mNameStr = "> " + conn.getData();
        if (sendToCli)
            srv.messageToPlayer(c, gaName, mNameStr);
        else
            srv.messageToGame(gaName, mNameStr);
    }
}
Also used : ArrayList(java.util.ArrayList) Connection(soc.server.genericServer.Connection) StringConnection(soc.server.genericServer.StringConnection) SQLException(java.sql.SQLException) MissingResourceException(java.util.MissingResourceException)

Example 27 with Connection

use of soc.server.genericServer.Connection in project JSettlers2 by jdmonin.

the class SOCServerMessageHandler method handleIMAROBOT.

/**
 * Handle the "I'm a robot" message.
 * Robots send their {@link SOCVersion} before sending this message.
 * Their version is checked here, must equal server's version.
 * For stability and control, the cookie in this message must
 * match this server's {@link SOCServer#robotCookie}.
 * Otherwise the bot is rejected and they're disconnected by calling
 * {@link SOCServer#removeConnection(Connection, boolean)}.
 *<P>
 * Bot tuning parameters are sent here to the bot, from
 * {@link SOCDBHelper#retrieveRobotParams(String, boolean) SOCDBHelper.retrieveRobotParams(botName, true)}.
 * See that method for default bot params.
 * See {@link SOCServer#authOrRejectClientRobot(Connection, String, String, String)}
 * for {@link SOCClientData} flags and fields set for the bot's connection
 * and for other misc work done, such as {@link Server#cliConnDisconPrintsPending} updates.
 *<P>
 * The server's built-in bots are named and started in {@link SOCServer#setupLocalRobots(int, int)},
 * then must authenticate with this message just like external or third-party bots.
 *
 * @param c  the connection that sent the message
 * @param mes  the message
 * @since 1.0.0
 */
private void handleIMAROBOT(final Connection c, final SOCImARobot mes) {
    if (c == null)
        return;
    final String botName = mes.getNickname();
    final String rejectReason = srv.authOrRejectClientRobot(c, botName, mes.getCookie(), mes.getRBClass());
    if (rejectReason != null) {
        if (rejectReason.equals(SOCServer.MSG_NICKNAME_ALREADY_IN_USE))
            c.put(SOCStatusMessage.toCmd(SOCStatusMessage.SV_NAME_IN_USE, c.getVersion(), rejectReason));
        c.put(new SOCRejectConnection(rejectReason).toCmd());
        c.disconnectSoft();
        // make an effort to send reject message before closing socket
        final Connection rc = c;
        srv.miscTaskTimer.schedule(new TimerTask() {

            public void run() {
                srv.removeConnection(rc, true);
            }
        }, 300);
        // <--- Early return: rejected ---
        return;
    }
    // 
    // send the current robot parameters
    // 
    SOCRobotParameters params = null;
    try {
        params = SOCDBHelper.retrieveRobotParams(botName, true);
        // or srv.ROBOT_PARAMS_DEFAULT (SOCRobotDM.FAST_STRATEGY).
        if ((params != null) && (params != SOCServer.ROBOT_PARAMS_SMARTER) && (params != SOCServer.ROBOT_PARAMS_DEFAULT) && D.ebugIsEnabled())
            D.ebugPrintln("*** Robot Parameters for " + botName + " = " + params);
    } catch (SQLException sqle) {
        System.err.println("Error retrieving robot parameters from db: Using defaults.");
    }
    if (params == null)
        // fallback in case of SQLException
        params = SOCServer.ROBOT_PARAMS_DEFAULT;
    c.put(SOCUpdateRobotParams.toCmd(params));
}
Also used : TimerTask(java.util.TimerTask) SQLException(java.sql.SQLException) Connection(soc.server.genericServer.Connection) StringConnection(soc.server.genericServer.StringConnection) SOCRobotParameters(soc.util.SOCRobotParameters)

Example 28 with Connection

use of soc.server.genericServer.Connection in project JSettlers2 by jdmonin.

the class SOCServerMessageHandler method handleRESETBOARDREQUEST.

/**
 * handle "reset-board request" message.
 * If {@link SOCGame#getResetVoteActive()} already or {@link SOCPlayer#hasAskedBoardReset()} this turn,
 * ignore. Otherwise: If multiple human players, start a vote with {@link SOCGame#resetVoteBegin(int)}.
 * If requester is sole human player, reset the game to a copy with same name and (copy of) same players,
 * new layout, by calling {@link SOCServer#resetBoardAndNotify(String, int)}.
 *<P>
 * The requesting player doesn't vote, but server still sends them a vote-request message to tell that client their
 * request was accepted and voting has begun.
 *<P>
 * If only one player remains (all other humans have left at end), ask them to start a new game instead.
 * This is a rare occurrence and we shouldn't bring in new robots and all,
 * since we already have an interface to set up a game.
 *<P>
 * If any human player's client is too old to vote for reset, assume they vote Yes.
 *
 * @param c  the connection
 * @param mes  the message
 * @see #handleRESETBOARDVOTE(Connection, SOCResetBoardVote)
 * @since 1.1.00
 */
private void handleRESETBOARDREQUEST(Connection c, final SOCResetBoardRequest mes) {
    final String gaName = mes.getGame();
    SOCGame ga = gameList.getGameData(gaName);
    if (ga == null)
        return;
    SOCPlayer reqPlayer = ga.getPlayer(c.getData());
    if (reqPlayer == null) {
        // Not playing in that game (Security)
        return;
    }
    /**
     * Is voting already active from another player?
     * Or, has this player already asked for voting this turn?
     */
    if (ga.getResetVoteActive() || reqPlayer.hasAskedBoardReset()) {
        // that would end the already-active round of voting.
        return;
    }
    /**
     * Is there more than one human player?
     * Grab connection information for humans and robots.
     */
    Connection[] humanConns = new Connection[ga.maxPlayers];
    Connection[] robotConns = new Connection[ga.maxPlayers];
    final int numHuman = SOCGameBoardReset.sortPlayerConnections(ga, null, gameList.getMembers(gaName), humanConns, robotConns);
    final int reqPN = reqPlayer.getPlayerNumber();
    if (numHuman < 2) {
        // Are there robots? Go ahead and reset if so.
        boolean hadRobot = false, hadUnlockedRobot = false;
        for (int i = robotConns.length - 1; i >= 0; --i) {
            if (robotConns[i] != null) {
                hadRobot = true;
                if (ga.getSeatLock(i) == SOCGame.SeatLockState.UNLOCKED) {
                    hadUnlockedRobot = true;
                    break;
                }
            }
        }
        if (hadUnlockedRobot) {
            srv.resetBoardAndNotify(gaName, reqPN);
        } else if (hadRobot) {
            srv.messageToPlayerKeyed(c, gaName, "resetboard.request.unlock.bot");
        // "Please unlock at least one bot, so you will have an opponent."
        } else {
            srv.messageToGameKeyed(ga, true, "resetboard.request.everyone.left");
        // "Everyone has left this game. Please start a new game with players or bots."
        }
    } else {
        // Probably put it to a vote.
        gameList.takeMonitorForGame(gaName);
        // First, Count number of other players who can vote (connected, version chk)
        int votingPlayers = 0;
        for (int i = ga.maxPlayers - 1; i >= 0; --i) {
            if ((i != reqPN) && !ga.isSeatVacant(i)) {
                Connection pc = srv.getConnection(ga.getPlayer(i).getName());
                if ((pc != null) && pc.isConnected() && (pc.getVersion() >= 1100))
                    ++votingPlayers;
            }
        }
        if (votingPlayers == 0) {
            // No one else is capable of voting.
            // Reset the game immediately.
            srv.messageToGameKeyed(ga, false, "resetboard.vote.request.alloldcli", c.getData());
            // ">>> {0} is resetting the game - other connected players are unable to vote (client too old)."
            gameList.releaseMonitorForGame(gaName);
            srv.resetBoardAndNotify(gaName, reqPN);
        } else {
            // Put it to a vote
            srv.messageToGameKeyed(ga, false, "resetboard.vote.request", c.getData());
            // "requests a board reset - other players please vote."
            String vrCmd = SOCResetBoardVoteRequest.toCmd(gaName, reqPN);
            ga.resetVoteBegin(reqPN);
            gameList.releaseMonitorForGame(gaName);
            for (int i = 0; i < ga.maxPlayers; ++i) if (humanConns[i] != null)
                if (humanConns[i].getVersion() >= 1100)
                    humanConns[i].put(vrCmd);
                else
                    ga.resetVoteRegister(ga.getPlayer(humanConns[i].getData()).getPlayerNumber(), true);
        }
    }
}
Also used : Connection(soc.server.genericServer.Connection) StringConnection(soc.server.genericServer.StringConnection) SOCPlayer(soc.game.SOCPlayer) SOCGame(soc.game.SOCGame)

Example 29 with Connection

use of soc.server.genericServer.Connection in project JSettlers2 by jdmonin.

the class SOCGameListAtServer method playerGamesMinVersion.

/**
 * For the games this player is in, what's the
 * minimum required client version?
 * Checks {@link SOCGame#getClientVersionMinRequired()}.
 *<P>
 * This method helps determine if a client's connection can be
 * "taken over" after a network problem.  It synchronizes on <tt>gameData</tt>.
 *
 * @param  plConn   the previous connection of the player, which might be taken over
 * @return Minimum version, in same format as {@link SOCGame#getClientVersionMinRequired()},
 *         or 0 if player isn't in any games.
 * @since 1.1.08
 */
public int playerGamesMinVersion(Connection plConn) {
    int minVers = 0;
    synchronized (gameData) {
        for (SOCGame ga : getGamesData()) {
            Vector<Connection> members = getMembers(ga.getName());
            if ((members == null) || !members.contains(plConn))
                continue;
            // plConn is a member of this game.
            int vers = ga.getClientVersionMinRequired();
            if (vers > minVers)
                minVers = vers;
        }
    }
    return minVers;
}
Also used : Connection(soc.server.genericServer.Connection) SOCGame(soc.game.SOCGame)

Example 30 with Connection

use of soc.server.genericServer.Connection in project JSettlers2 by jdmonin.

the class SOCGameListAtServer method removeMember.

/**
 * remove member from the game.
 * Also updates game's client version range, with remaining connected members.
 * Please call {@link #takeMonitorForGame(String)} before calling this.
 *
 * @param  gaName   the name of the game
 * @param  conn     the member's connection
 */
public synchronized void removeMember(Connection conn, String gaName) {
    Vector<Connection> members = getMembers(gaName);
    if ((members != null)) {
        members.removeElement(conn);
        // Check version of remaining members
        if (!members.isEmpty()) {
            Connection c = members.firstElement();
            int lowVers = c.getVersion();
            int highVers = lowVers;
            for (int i = members.size() - 1; i >= 1; --i) {
                c = members.elementAt(i);
                int v = c.getVersion();
                if (v < lowVers)
                    lowVers = v;
                if (v > highVers)
                    highVers = v;
            }
            SOCGame ga = getGameData(gaName);
            ga.clientVersionLowest = lowVers;
            ga.clientVersionHighest = highVers;
            ga.hasOldClients = (lowVers < Version.versionNumber());
        }
    }
}
Also used : Connection(soc.server.genericServer.Connection) SOCGame(soc.game.SOCGame)

Aggregations

Connection (soc.server.genericServer.Connection)44 StringConnection (soc.server.genericServer.StringConnection)24 SQLException (java.sql.SQLException)8 MissingResourceException (java.util.MissingResourceException)8 SOCGame (soc.game.SOCGame)7 EOFException (java.io.EOFException)5 IOException (java.io.IOException)5 SocketException (java.net.SocketException)5 ArrayList (java.util.ArrayList)5 SOCPlayerElement (soc.message.SOCPlayerElement)5 DBSettingMismatchException (soc.server.database.DBSettingMismatchException)5 SOCPlayer (soc.game.SOCPlayer)4 Date (java.util.Date)3 SOCGameElements (soc.message.SOCGameElements)3 HashSet (java.util.HashSet)2 Hashtable (java.util.Hashtable)2 TimerTask (java.util.TimerTask)2 Vector (java.util.Vector)2 SOCDevCardAction (soc.message.SOCDevCardAction)2 SOCInventoryItemAction (soc.message.SOCInventoryItemAction)2