1 /*****************************************************************************
2  * PokerTH - The open source texas holdem engine                             *
3  * Copyright (C) 2006-2012 Felix Hammer, Florian Thauer, Lothar May          *
4  *                                                                           *
5  * This program is free software: you can redistribute it and/or modify      *
6  * it under the terms of the GNU Affero General Public License as            *
7  * published by the Free Software Foundation, either version 3 of the        *
8  * License, or (at your option) any later version.                           *
9  *                                                                           *
10  * This program is distributed in the hope that it will be useful,           *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
13  * GNU Affero General Public License for more details.                       *
14  *                                                                           *
15  * You should have received a copy of the GNU Affero General Public License  *
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.     *
17  *                                                                           *
18  *                                                                           *
19  * Additional permission under GNU AGPL version 3 section 7                  *
20  *                                                                           *
21  * If you modify this program, or any covered work, by linking or            *
22  * combining it with the OpenSSL project's OpenSSL library (or a             *
23  * modified version of that library), containing parts covered by the        *
24  * terms of the OpenSSL or SSLeay licenses, the authors of PokerTH           *
25  * (Felix Hammer, Florian Thauer, Lothar May) grant you additional           *
26  * permission to convey the resulting work.                                  *
27  * Corresponding Source for a non-source form of such a combination          *
28  * shall include the source code for the parts of OpenSSL used as well       *
29  * as that of the covered work.                                              *
30  *****************************************************************************/
31 /* Network server lobby thread. */
32 
33 #ifndef _SERVERLOBBYTHREAD_H_
34 #define _SERVERLOBBYTHREAD_H_
35 
36 #include <boost/asio.hpp>
37 #include <boost/asio/steady_timer.hpp>
38 #include <boost/enable_shared_from_this.hpp>
39 #include <boost/uuid/uuid_generators.hpp>
40 
41 #include <net/sessionmanager.h>
42 #include <net/netpacket.h>
43 #include <db/serverdbcallback.h>
44 #include <gui/guiinterface.h>
45 #include <gamedata.h>
46 
47 #define NET_LOBBY_THREAD_TERMINATE_TIMEOUT_MSEC		20000
48 #define NET_ADMIN_IRC_TERMINATE_TIMEOUT_MSEC		4000
49 
50 
51 class SenderHelper;
52 class InternalServerCallback;
53 class ServerIrcBotCallback;
54 class ServerGame;
55 class ServerBanManager;
56 class ConfigFile;
57 class AvatarManager;
58 class ChatCleanerManager;
59 class ServerDBInterface;
60 struct GameData;
61 class Game;
62 struct Gsasl;
63 
64 class ServerLobbyThread : public Thread, public boost::enable_shared_from_this<ServerLobbyThread>
65 {
66 public:
67 	ServerLobbyThread(GuiInterface &gui, ServerMode mode, ServerIrcBotCallback &ircBotCb, ConfigFile &serverConfig, AvatarManager &avatarManager,
68 					  boost::shared_ptr<boost::asio::io_service> ioService);
69 	virtual ~ServerLobbyThread();
70 
71 	void Init(const std::string &logDir);
72 	virtual void SignalTermination();
73 
74 	void AddConnection(boost::shared_ptr<SessionData> sessionData);
75 	void ReAddSession(boost::shared_ptr<SessionData> session, int reason, unsigned gameId);
76 	void MoveSessionToGame(boost::shared_ptr<ServerGame> game, boost::shared_ptr<SessionData> session, bool autoLeave, bool spectateOnly);
77 	void SessionError(boost::shared_ptr<SessionData> session, int errorCode);
78 	void ResubscribeLobbyMsg(boost::shared_ptr<SessionData> session);
79 	void NotifyPlayerJoinedLobby(unsigned playerId);
80 	void NotifyPlayerLeftLobby(unsigned playerId);
81 	void NotifyPlayerJoinedGame(unsigned gameId, unsigned playerId);
82 	void NotifyPlayerLeftGame(unsigned gameId, unsigned playerId);
83 	void NotifySpectatorJoinedGame(unsigned gameId, unsigned playerId);
84 	void NotifySpectatorLeftGame(unsigned gameId, unsigned playerId);
85 	void NotifyGameAdminChanged(unsigned gameId, unsigned newAdminPlayerId);
86 	void NotifyStartingGame(unsigned gameId);
87 	void NotifyReopeningGame(unsigned gameId);
88 
89 	void DispatchPacket(boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet);
90 	void HandleGameRetrievePlayerInfo(boost::shared_ptr<SessionData> session, const PlayerInfoRequestMessage &playerInfoRequest);
91 	void HandleGameRetrieveAvatar(boost::shared_ptr<SessionData> session, const AvatarRequestMessage &retrieveAvatar);
92 	void HandleGameReportGame(boost::shared_ptr<SessionData> session, const ReportGameMessage &reportGame);
93 	void HandleChatRequest(boost::shared_ptr<SessionData> session, const ChatRequestMessage &chatRequest);
94 	void HandleAdminRemoveGame(boost::shared_ptr<SessionData> session, const AdminRemoveGameMessage &removeGame);
95 	void HandleAdminBanPlayer(boost::shared_ptr<SessionData> session, const AdminBanPlayerMessage &banPlayer);
96 
97 	bool KickPlayerByName(const std::string &playerName);
98 	bool RemoveGameByPlayerName(const std::string &playerName);
99 	std::string GetPlayerIPAddress(const std::string &playerName) const;
100 	std::string GetPlayerNameFromId(unsigned playerId) const;
101 	void RemovePlayer(unsigned playerId, unsigned errorCode);
102 	void MutePlayerInGame(unsigned playerId);
103 
104 	void SendGlobalChat(const std::string &message);
105 	void SendGlobalMsgBox(const std::string &message);
106 	void SendChatBotMsg(const std::string &message);
107 	void SendChatBotMsg(unsigned gameId, const std::string &message);
108 	void ReconnectChatBot();
109 
110 	void AddComputerPlayer(boost::shared_ptr<PlayerData> player);
111 	void RemoveComputerPlayer(boost::shared_ptr<PlayerData> player);
112 
113 	bool SendToLobbyPlayer(unsigned playerId, boost::shared_ptr<NetPacket> packet);
114 
115 	u_int32_t GetNextSessionId();
116 	u_int32_t GetNextUniquePlayerId();
117 	u_int32_t GetNextGameId();
118 	ServerCallback &GetCallback();
119 
120 	AvatarManager &GetAvatarManager();
121 	ChatCleanerManager &GetChatCleaner();
122 
123 	ServerStats GetStats() const;
124 	boost::posix_time::ptime GetStartTime() const;
125 	ServerMode GetServerMode() const;
126 
127 	SenderHelper &GetSender();
128 	boost::asio::io_service &GetIOService();
129 	boost::shared_ptr<ServerDBInterface> GetDatabase();
130 	ServerBanManager &GetBanManager();
131 
132 	SessionDataCallback &GetSessionDataCallback();
133 
134 protected:
135 
136 	typedef std::deque<boost::shared_ptr<boost::asio::ip::tcp::socket> > ConnectQueue;
137 	typedef std::list<boost::shared_ptr<SessionData> > SessionList;
138 	typedef std::list<SessionId> SessionIdList;
139 	typedef std::map<SessionId, boost::timers::portable::microsec_timer> TimerSessionMap;
140 	typedef std::map<unsigned, boost::shared_ptr<ServerGame> > GameMap;
141 	typedef std::map<std::string, boost::timers::portable::microsec_timer> TimerClientAddressMap;
142 	typedef std::list<unsigned> RemoveGameList;
143 
144 	// Main function of the thread.
145 	virtual void Main();
146 	void RegisterTimers();
147 	void CancelTimers();
148 	void InitAuthContext();
149 	void ClearAuthContext();
150 	void InitChatCleaner();
151 
152 	void HandlePacket(boost::shared_ptr<SessionData> session, boost::shared_ptr<NetPacket> packet);
153 	void HandleNetPacketInit(boost::shared_ptr<SessionData> session, const InitMessage &initMessage);
154 	void HandleNetPacketAuthClientResponse(boost::shared_ptr<SessionData> session, const AuthClientResponseMessage &clientResponse);
155 	void HandleNetPacketAvatarHeader(boost::shared_ptr<SessionData> session, const AvatarHeaderMessage &avatarHeader);
156 	void HandleNetPacketUnknownAvatar(boost::shared_ptr<SessionData> session, const UnknownAvatarMessage &unknownAvatar);
157 	void HandleNetPacketAvatarFile(boost::shared_ptr<SessionData> session, const AvatarDataMessage &avatarData);
158 	void HandleNetPacketAvatarEnd(boost::shared_ptr<SessionData> session, const AvatarEndMessage &avatarEnd);
159 	void HandleNetPacketRetrievePlayerInfo(boost::shared_ptr<SessionData> session, const PlayerInfoRequestMessage &playerInfoRequest);
160 	void HandleNetPacketRetrieveAvatar(boost::shared_ptr<SessionData> session, const AvatarRequestMessage &retrieveAvatar);
161 	void HandleNetPacketCreateGame(boost::shared_ptr<SessionData> session, const JoinNewGameMessage &newGame);
162 	void HandleNetPacketJoinGame(boost::shared_ptr<SessionData> session, const JoinExistingGameMessage &joinGame);
163 	void HandleNetPacketRejoinGame(boost::shared_ptr<SessionData> session, const RejoinExistingGameMessage &rejoinGame);
164 	void HandleNetPacketChatRequest(boost::shared_ptr<SessionData> session, const ChatRequestMessage &chatRequest);
165 	void HandleNetPacketRejectGameInvitation(boost::shared_ptr<SessionData> session, const RejectGameInvitationMessage &reject);
166 	void HandleNetPacketReportGame(boost::shared_ptr<SessionData> session, const ReportGameMessage &report);
167 	void HandleNetPacketAdminRemoveGame(boost::shared_ptr<SessionData> session, const AdminRemoveGameMessage &removeGame);
168 	void HandleNetPacketAdminBanPlayer(boost::shared_ptr<SessionData> session, const AdminBanPlayerMessage &banPlayer);
169 	// TODO would be better to use state pattern here.
170 	void AuthChallenge(boost::shared_ptr<SessionData> session, const std::string &secret);
171 	void CheckAvatarBlacklist(boost::shared_ptr<SessionData> session);
172 	void AvatarBlacklisted(unsigned playerId);
173 	void AvatarOK(unsigned playerId);
174 	void InitAfterLogin(boost::shared_ptr<SessionData> session);
175 	void EstablishSession(boost::shared_ptr<SessionData> session);
176 	void AuthenticatePlayer(boost::shared_ptr<SessionData> session);
177 	void UserValid(unsigned playerId, const DBPlayerData &dbPlayerData);
178 	void UserInvalid(unsigned playerId);
179 	void UserBlocked(unsigned playerId);
180 
181 	void SendReportAvatarResult(unsigned byPlayerId, unsigned reportedPlayerId, bool success);
182 	void SendReportGameResult(unsigned byPlayerId, unsigned reportedGameId, bool success);
183 	void SendAdminBanPlayerResult(unsigned byPlayerId, unsigned reportedPlayerId, bool success);
184 	void RequestPlayerAvatar(boost::shared_ptr<SessionData> session);
185 	void TimerRemoveGame(const boost::system::error_code &ec);
186 	void TimerRemovePlayer(const boost::system::error_code &ec);
187 	void TimerUpdateClientLoginLock(const boost::system::error_code &ec);
188 	void TimerCleanupAvatarCache(const boost::system::error_code &ec);
189 
190 	bool IsGameNameInUse(const std::string &gameName) const;
191 	boost::shared_ptr<ServerGame> InternalGetGameFromId(unsigned gameId);
192 	void InternalAddGame(boost::shared_ptr<ServerGame> game);
193 	void InternalRemoveGame(boost::shared_ptr<ServerGame> game);
194 	void InternalRemovePlayer(unsigned playerId, unsigned errorCode);
195 	void InternalMutePlayerInGame(unsigned playerId);
196 	void InternalResubscribeMsg(boost::shared_ptr<SessionData> session);
197 
198 	void HandleReAddedSession(boost::shared_ptr<SessionData> session);
199 
200 	void SessionTimeoutWarning(boost::shared_ptr<SessionData> session, unsigned remainingSec);
201 
202 	void CleanupSessionMap();
203 
204 	void CloseSession(boost::shared_ptr<SessionData> session);
205 	void SendError(boost::shared_ptr<SessionData> s, int errorCode);
206 	void SendJoinGameFailed(boost::shared_ptr<SessionData> s, unsigned gameId, int reason);
207 	void SendPlayerList(boost::shared_ptr<SessionData> s);
208 	void SendGameList(boost::shared_ptr<SessionData> s);
209 	void UpdateStatisticsNumberOfPlayers();
210 	void BroadcastStatisticsUpdate(const ServerStats &stats);
211 
212 	void ReadStatisticsFile();
213 	void TimerSaveStatisticsFile(const boost::system::error_code &ec);
214 
215 	InternalServerCallback &GetSenderCallback();
216 	GuiInterface &GetGui();
217 	ServerIrcBotCallback &GetIrcBotCallback();
218 
219 	unsigned GetPlayerId(const std::string &name) const;
220 
221 	static boost::shared_ptr<NetPacket> CreateNetPacketPlayerListNew(unsigned playerId);
222 	static boost::shared_ptr<NetPacket> CreateNetPacketPlayerListLeft(unsigned playerId);
223 	static boost::shared_ptr<NetPacket> CreateNetPacketGameListNew(const ServerGame &game);
224 	static boost::shared_ptr<NetPacket> CreateNetPacketGameListUpdate(unsigned gameId, GameMode mode);
225 
226 	u_int32_t GetRejoinGameIdForPlayer(const std::string &playerName, const std::string &guid, unsigned &outPlayerUniqueId);
227 
228 private:
229 
230 	boost::shared_ptr<boost::asio::io_service> m_ioService;
231 
232 	boost::shared_ptr<InternalServerCallback> m_internalServerCallback;
233 	boost::shared_ptr<SenderHelper> m_sender;
234 
235 	SessionManager m_sessionManager;
236 	SessionManager m_gameSessionManager;
237 
238 	Gsasl *m_authContext;
239 
240 	TimerClientAddressMap m_timerClientAddressMap;
241 	mutable boost::mutex m_timerClientAddressMapMutex;
242 
243 	RemoveGameList m_removeGameList;
244 	mutable boost::mutex m_removeGameListMutex;
245 
246 	PlayerDataMap m_computerPlayers;
247 	mutable boost::mutex m_computerPlayersMutex;
248 
249 	GameMap m_gameMap;
250 
251 	GuiInterface &m_gui;
252 	ServerIrcBotCallback &m_ircBotCb;
253 	AvatarManager &m_avatarManager;
254 
255 	const ServerMode m_mode;
256 	std::string m_statisticsFileName;
257 	ConfigFile &m_serverConfig;
258 	u_int32_t m_curGameId;
259 
260 	u_int32_t m_curUniquePlayerId;
261 	u_int32_t m_curSessionId;
262 	mutable boost::mutex m_curUniquePlayerIdMutex;
263 
264 	ServerStats m_statData;
265 	bool m_statDataChanged;
266 	mutable boost::mutex m_statMutex;
267 
268 	boost::shared_ptr<ServerBanManager> m_banManager;
269 	boost::shared_ptr<ChatCleanerManager> m_chatCleanerManager;
270 	boost::shared_ptr<ServerDBInterface> m_database;
271 
272 	boost::asio::steady_timer m_removeGameTimer;
273 	boost::asio::steady_timer m_saveStatisticsTimer;
274 	boost::asio::steady_timer m_loginLockTimer;
275 
276 	boost::uuids::random_generator m_sessionIdGenerator;
277 
278 	const boost::posix_time::ptime m_startTime;
279 
280 	friend class InternalServerCallback;
281 };
282 
283 #endif
284