Search in sources :

Example 21 with Connection

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

the class SOCServer method setClientVersSendGamesOrReject.

/**
 * Set client's version and locale, and check against minimum required version {@link #CLI_VERSION_MIN}.
 * If version is too low, send {@link SOCRejectConnection REJECTCONNECTION}
 * and call {@link #removeConnection(Connection, boolean)}.
 * If we haven't yet sent the game list, send now.
 * If we've already sent the game list, send changes based on true version.
 *<P>
 * Along with the game list, the client will need to know the game option info.
 * This is sent when the client asks (after VERSION) for {@link SOCGameOptionGetInfos GAMEOPTIONGETINFOS}.
 * Game options are sent after client version is known, so the list of
 * sent options is based on client version.
 *<P>
 *<B>I18N:</B> If client doesn't send a locale string, the default locale {@code en_US} is used.
 * Robot clients will get the default locale and localeStr here; those will be cleared to {@code null} by
 * {@link #authOrRejectClientRobot(Connection, String, String, String)} when the bot sends {@link SOCImARobot}.
 *<P>
 *<b>Locks:</b> To set the version, will synchronize briefly on {@link Server#unnamedConns unnamedConns}.
 * If {@link Connection#getVersion() c.getVersion()} is already == cvers,
 * don't bother to lock and set it.
 *<P>
 * Package access (not private) is strictly for use of {@link SOCServerMessageHandler}
 * and {@link SOCClientData.SOCCDCliVersionTask#run()}.
 *
 * @param c     Client's connection
 * @param cvers Version reported by client, or assumed version if no report
 * @param clocale  Locale reported by client, or null if none given (was added to {@link SOCVersion} in 2.0.00)
 * @param isKnown Is this the client's definite version, or just an assumed one?
 *                Affects {@link Connection#isVersionKnown() c.isVersionKnown}.
 *                Can set the client's known version only once; a second "known" call with
 *                a different cvers will be rejected.
 * @return True if OK, false if rejected
 */
boolean setClientVersSendGamesOrReject(Connection c, final int cvers, String clocale, final boolean isKnown) {
    final int prevVers = c.getVersion();
    final boolean wasKnown = c.isVersionKnown();
    SOCClientData scd = (SOCClientData) c.getAppData();
    // Message to send/log if client must be disconnected
    String rejectMsg = null;
    String rejectLogMsg = null;
    if (clocale == null)
        // backwards compatibility with clients older than v2.0.00
        clocale = "en_US";
    final int hashIdx = clocale.indexOf("_#");
    if (hashIdx != -1) {
        // extended info from java 1.7+ Locale.toString();
        // if our server is an older JRE version, strip that out.
        final String jreVersStr = System.getProperty("java.specification.version");
        if (jreVersStr.startsWith("1.5") || jreVersStr.startsWith("1.6")) {
            clocale = clocale.substring(0, hashIdx);
        }
    }
    scd.localeStr = clocale;
    try {
        scd.locale = I18n.parseLocale(clocale);
    } catch (IllegalArgumentException e) {
        rejectMsg = "Sorry, cannot parse your locale.";
        // unsanitized data, don't print clocale to log
        rejectLogMsg = "Rejected client: Cannot parse locale";
    }
    c.setI18NStringManager(SOCStringManager.getServerManagerForClient(scd.locale), clocale);
    if (prevVers == -1)
        scd.clearVersionTimer();
    if (prevVers != cvers) {
        synchronized (unnamedConns) {
            c.setVersion(cvers, isKnown);
        }
    } else if (wasKnown) {
        // <--- Early return: Already knew it ----
        return true;
    }
    if (cvers < CLI_VERSION_MIN) {
        if (cvers > 0)
            rejectMsg = "Sorry, your client version number " + cvers + " is too old, version ";
        else
            rejectMsg = "Sorry, your client version is too old, version number ";
        rejectMsg += Integer.toString(CLI_VERSION_MIN) + " (" + CLI_VERSION_MIN_DISPLAY + ") or above is required.";
        rejectLogMsg = "Rejected client: Version " + cvers + " too old";
    }
    if (wasKnown && isKnown && (cvers != prevVers)) {
        // can't change the version once known
        rejectMsg = "Sorry, cannot report two different versions.";
        rejectLogMsg = "Rejected client: Already gave VERSION(" + prevVers + "), now says VERSION(" + cvers + ")";
    }
    if (rejectMsg != null) {
        c.put(new SOCRejectConnection(rejectMsg).toCmd());
        c.disconnectSoft();
        System.out.println(rejectLogMsg);
        // make an effort to send reject message before closing socket
        final Connection rc = c;
        miscTaskTimer.schedule(new TimerTask() {

            public void run() {
                removeConnection(rc, true);
            }
        }, 300);
        // <--- Early return: Rejected client ---
        return false;
    }
    // Send game list?
    // Will check c.getAppData().hasSentGameList() flag.
    // prevVers is ignored unless already sent game list.
    sendGameList(c, prevVers);
    // This will be displayed in the client's status line (v1.1.17 and newer).
    if (allowDebugUser)
        c.put(SOCStatusMessage.toCmd(SOCStatusMessage.SV_OK_DEBUG_MODE_ON, cvers, // "Debugging is On.  Welcome to Java Settlers of Catan!"
        c.getLocalized("member.welcome.debug")));
    // Increment version stats; currently assumes single-threaded access to the map.
    // We don't know yet if client is a bot, so bots are included in the stats.
    // (If this is not wanted, the bot could be subtracted at handleIMAROBOT.)
    final Integer cversObj = Integer.valueOf(cvers);
    final int prevCount;
    Integer prevCObj = clientPastVersionStats.get(cversObj);
    prevCount = (prevCObj != null) ? prevCObj.intValue() : 0;
    clientPastVersionStats.put(cversObj, Integer.valueOf(1 + prevCount));
    // This client version is OK to connect
    return true;
}
Also used : TimerTask(java.util.TimerTask) StringConnection(soc.server.genericServer.StringConnection) Connection(soc.server.genericServer.Connection)

Example 22 with Connection

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

the class SOCServer method destroyGame.

/**
 * Destroy a game and clean up related data, such as the owner's count of
 * {@link SOCClientData#getCurrentCreatedGames()}.
 *<P>
 * Note that if this game had the {@link SOCGame#isBotsOnly} flag, and {@link #numRobotOnlyGamesRemaining} &gt; 0,
 * will call {@link #startRobotOnlyGames(boolean)}.
 *<P>
 * <B>Locks:</B> Must have {@link #gameList}{@link SOCGameList#takeMonitor() .takeMonitor()}
 * before calling this method.
 *
 * @param gm  Name of the game to destroy
 * @see #leaveGame(Connection, String, boolean, boolean)
 * @see #destroyGameAndBroadcast(String, String)
 */
public void destroyGame(String gm) {
    // D.ebugPrintln("***** destroyGame("+gm+")");
    SOCGame cg = null;
    cg = gameList.getGameData(gm);
    if (cg == null)
        return;
    final boolean wasBotsOnly = cg.isBotsOnly;
    // /
    // / write out game data
    // /
    /*
           currentGameEventRecord.setSnapshot(cg);
           saveCurrentGameEventRecord(gm);
           SOCGameRecord gr = (SOCGameRecord)gameRecords.get(gm);
           writeGameRecord(gm, gr);
         */
    // /
    // / delete the game from gamelist,
    // / tell all robots to leave
    // /
    Vector<Connection> members = null;
    members = gameList.getMembers(gm);
    // also calls SOCGame.destroyGame
    gameList.deleteGame(gm);
    if (members != null) {
        Enumeration<Connection> conEnum = members.elements();
        while (conEnum.hasMoreElements()) {
            Connection con = conEnum.nextElement();
            con.put(SOCRobotDismiss.toCmd(gm));
        }
    }
    // Reduce the owner's games-active count
    final String gaOwner = cg.getOwner();
    if (gaOwner != null) {
        Connection oConn = conns.get(gaOwner);
        if (oConn != null)
            ((SOCClientData) oConn.getAppData()).deletedGame();
    }
    if (wasBotsOnly && (numRobotOnlyGamesRemaining > 0))
        startRobotOnlyGames(true);
}
Also used : StringConnection(soc.server.genericServer.StringConnection) Connection(soc.server.genericServer.Connection)

Example 23 with Connection

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

the class SOCServer method messageToGame.

/**
 * Send a message to the given game.
 *<P>
 * <b>Locks:</b> Takes, releases {@link SOCGameList#takeMonitorForGame(String)}.
 *
 * @param ga  the name of the game
 * @param mes the message to send. If mes is a SOCGameTextMsg whose
 *            text begins with ">>>", the client should consider this
 *            an urgent message, and draw the user's attention in some way.
 *            (See {@link #messageToGameUrgent(String, String)})
 * @see #messageToGame(String, String)
 * @see #messageToGameWithMon(String, SOCMessage)
 * @see #messageToGameForVersions(SOCGame, int, int, SOCMessage, boolean)
 */
public void messageToGame(String ga, SOCMessage mes) {
    final String mesCmd = mes.toCmd();
    gameList.takeMonitorForGame(ga);
    try {
        Vector<Connection> v = gameList.getMembers(ga);
        if (v != null) {
            // D.ebugPrintln("M2G - "+mes);
            Enumeration<Connection> menum = v.elements();
            while (menum.hasMoreElements()) {
                Connection c = menum.nextElement();
                if (c != null) {
                    // currentGameEventRecord.addMessageOut(new SOCMessageRecord(mes, "SERVER", c.getData()));
                    c.put(mesCmd);
                }
            }
        }
    } catch (Exception e) {
        D.ebugPrintStackTrace(e, "Exception in messageToGame");
    }
    gameList.releaseMonitorForGame(ga);
}
Also used : StringConnection(soc.server.genericServer.StringConnection) Connection(soc.server.genericServer.Connection) MissingResourceException(java.util.MissingResourceException) EOFException(java.io.EOFException) DBSettingMismatchException(soc.server.database.DBSettingMismatchException) SocketException(java.net.SocketException) SQLException(java.sql.SQLException) IOException(java.io.IOException)

Example 24 with Connection

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

the class SOCServerRobotPinger method run.

/**
 * Robot ping loop thread:
 * Send a {@link SOCServerPing} to each bot connected to the server,
 * then sleep for {@link #sleepTime} minus 60 seconds.
 * Exits loop when {@link #stopPinger()} is called.
 */
@Override
public void run() {
    final String pingCmdStr = ping.toCmd();
    while (alive) {
        boolean retry = false;
        if (!robotConnections.isEmpty()) {
            try {
                for (Connection robotConnection : robotConnections) {
                    if (D.ebugIsEnabled())
                        D.ebugPrintln("(*)(*)(*)(*) PINGING " + robotConnection.getData());
                    robotConnection.put(pingCmdStr);
                }
            } catch (ConcurrentModificationException e) {
                retry = true;
            }
        }
        yield();
        final int msec = (retry) ? 250 : (sleepTime - 60000);
        try {
            sleep(msec);
        } catch (InterruptedException exc) {
        }
    }
    // 
    // cleanup
    // 
    robotConnections = null;
}
Also used : ConcurrentModificationException(java.util.ConcurrentModificationException) Connection(soc.server.genericServer.Connection)

Example 25 with Connection

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

the class SOCServerMessageHandler method handleSITDOWN.

/**
 * handle "sit down" message
 *
 * @param c  the connection that sent the message
 * @param mes  the message
 * @since 1.0.0
 */
private void handleSITDOWN(Connection c, SOCSitDown mes) {
    if (c == null)
        return;
    final String gaName = mes.getGame();
    SOCGame ga = gameList.getGameData(gaName);
    if (ga == null) {
        // Out of date client info, or may be observing a deleted game.
        // Already authenticated (c != null), so replying is OK by security.
        // "Game not found."
        srv.messageToPlayerKeyed(c, gaName, "reply.game.not.found");
        // <--- Early return: No active game found ---
        return;
    }
    /**
     * make sure this player isn't already sitting
     */
    boolean canSit = true;
    boolean gameIsFull = false, gameAlreadyStarted = false;
    /*
           for (int i = 0; i < SOCGame.MAXPLAYERS; i++) {
           if (ga.getPlayer(i).getName() == c.getData()) {
           canSit = false;
           break;
           }
           }
         */
    // D.ebugPrintln("ga.isSeatVacant(mes.getPlayerNumber()) = "+ga.isSeatVacant(mes.getPlayerNumber()));
    /**
     * if this is a robot, remove it from the request list
     */
    boolean isBotJoinRequest = false;
    {
        Hashtable<Connection, Object> joinRequests = srv.robotJoinRequests.get(gaName);
        if (joinRequests != null)
            isBotJoinRequest = (null != joinRequests.remove(c));
    }
    /**
     * make sure a person isn't sitting here already;
     * if a robot is sitting there, dismiss the robot.
     * Can't sit at a vacant seat after everyone has
     * placed 1st settlement+road (state >= START2A).
     *
     * If a human leaves after game is started, seat will appear vacant when the
     * requested bot sits to replace them, so let the bot sit at that vacant seat.
     */
    final int pn = mes.getPlayerNumber();
    ga.takeMonitor();
    try {
        if (ga.isSeatVacant(pn)) {
            gameAlreadyStarted = (ga.getGameState() >= SOCGame.START2A);
            if (!gameAlreadyStarted)
                gameIsFull = (1 > ga.getAvailableSeatCount());
            if (gameIsFull || (gameAlreadyStarted && !isBotJoinRequest))
                canSit = false;
        } else {
            SOCPlayer seatedPlayer = ga.getPlayer(pn);
            if (seatedPlayer.isRobot() && (ga.getSeatLock(pn) != SOCGame.SeatLockState.LOCKED) && (ga.getCurrentPlayerNumber() != pn)) {
                /**
                 * boot the robot out of the game
                 */
                Connection robotCon = srv.getConnection(seatedPlayer.getName());
                robotCon.put(SOCRobotDismiss.toCmd(gaName));
                /**
                 * this connection has to wait for the robot to leave
                 * and then it can sit down
                 */
                Vector<SOCReplaceRequest> disRequests = srv.robotDismissRequests.get(gaName);
                SOCReplaceRequest req = new SOCReplaceRequest(c, robotCon, mes);
                if (disRequests == null) {
                    disRequests = new Vector<SOCReplaceRequest>();
                    disRequests.addElement(req);
                    srv.robotDismissRequests.put(gaName, disRequests);
                } else {
                    disRequests.addElement(req);
                }
            }
            canSit = false;
        }
    } catch (Exception e) {
        D.ebugPrintStackTrace(e, "Exception caught at handleSITDOWN");
    }
    ga.releaseMonitor();
    // D.ebugPrintln("canSit 2 = "+canSit);
    if (canSit) {
        srv.sitDown(ga, c, pn, mes.isRobot(), false);
    } else {
        /**
         * if the robot can't sit, tell it to go away.
         * otherwise if game is full, tell the player.
         */
        if (mes.isRobot()) {
            c.put(SOCRobotDismiss.toCmd(gaName));
        } else if (gameAlreadyStarted) {
            srv.messageToPlayerKeyed(c, gaName, "member.sit.game.started");
        // "This game has already started; to play you must take over a robot."
        } else if (gameIsFull) {
            srv.messageToPlayerKeyed(c, gaName, "member.sit.game.full");
        // "This game is full; you cannot sit down."
        }
    }
}
Also used : Hashtable(java.util.Hashtable) Connection(soc.server.genericServer.Connection) StringConnection(soc.server.genericServer.StringConnection) SOCPlayer(soc.game.SOCPlayer) SOCGame(soc.game.SOCGame) SQLException(java.sql.SQLException) MissingResourceException(java.util.MissingResourceException)

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