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 
32 #include <net/sessionmanager.h>
33 #include <net/senderhelper.h>
34 #include <net/serverexception.h>
35 #include <net/socket_msg.h>
36 
37 using namespace std;
38 
39 #define SERVER_MAX_GUEST_USERS_LOBBY	50		// LG: Maximum number of guests users in lobby allowed
40 
SessionManager()41 SessionManager::SessionManager()
42 {
43 }
44 
~SessionManager()45 SessionManager::~SessionManager()
46 {
47 	Clear();
48 }
49 
50 void
AddSession(boost::shared_ptr<SessionData> session)51 SessionManager::AddSession(boost::shared_ptr<SessionData> session)
52 {
53 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
54 
55 	SessionMap::iterator pos = m_sessionMap.lower_bound(session->GetId());
56 
57 	// If pos points to a pair whose key is equivalent to the socket, this handle
58 	// already exists within the list.
59 	if (pos != m_sessionMap.end() && session->GetId() == pos->first) {
60 		throw ServerException(__FILE__, __LINE__, ERR_SOCK_CONN_EXISTS, 0);
61 	}
62 	m_sessionMap.insert(pos, SessionMap::value_type(session->GetId(), session));
63 }
64 
65 void
SetSessionPlayerData(SessionId session,boost::shared_ptr<PlayerData> playerData)66 SessionManager::SetSessionPlayerData(SessionId session, boost::shared_ptr<PlayerData> playerData)
67 {
68 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
69 	SessionMap::iterator pos = m_sessionMap.find(session);
70 
71 	if (pos != m_sessionMap.end())
72 		pos->second->SetPlayerData(playerData);
73 }
74 
75 bool
RemoveSession(SessionId session)76 SessionManager::RemoveSession(SessionId session)
77 {
78 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
79 	return m_sessionMap.erase(session) == 1;
80 }
81 
82 boost::shared_ptr<SessionData>
GetSessionById(SessionId id) const83 SessionManager::GetSessionById(SessionId id) const
84 {
85 	boost::shared_ptr<SessionData> tmpSession;
86 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
87 	SessionMap::const_iterator pos = m_sessionMap.find(id);
88 	if (pos != m_sessionMap.end())
89 		tmpSession = pos->second;
90 	return tmpSession;
91 }
92 
93 boost::shared_ptr<SessionData>
GetSessionByPlayerName(const string & playerName) const94 SessionManager::GetSessionByPlayerName(const string &playerName) const
95 {
96 	boost::shared_ptr<SessionData> tmpSession;
97 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
98 
99 	SessionMap::const_iterator session_i = m_sessionMap.begin();
100 	SessionMap::const_iterator session_end = m_sessionMap.end();
101 
102 	while (session_i != session_end) {
103 		// Check all players which are fully connected.
104 		if (session_i->second->GetState() != SessionData::Init) {
105 			boost::shared_ptr<PlayerData> tmpPlayer(session_i->second->GetPlayerData());
106 			if (!tmpPlayer)
107 				throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0);
108 			if (tmpPlayer->GetName() == playerName) {
109 				tmpSession = session_i->second;
110 				break;
111 			}
112 		}
113 
114 		++session_i;
115 	}
116 	return tmpSession;
117 }
118 
119 boost::shared_ptr<SessionData>
GetSessionByUniquePlayerId(unsigned uniqueId,bool initSessions) const120 SessionManager::GetSessionByUniquePlayerId(unsigned uniqueId, bool initSessions) const
121 {
122 	boost::shared_ptr<SessionData> tmpSession;
123 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
124 
125 	SessionMap::const_iterator session_i = m_sessionMap.begin();
126 	SessionMap::const_iterator session_end = m_sessionMap.end();
127 
128 	while (session_i != session_end) {
129 		// Check all players which are fully connected.
130 		if (initSessions || session_i->second->GetState() != SessionData::Init) {
131 			boost::shared_ptr<PlayerData> tmpPlayer(session_i->second->GetPlayerData());
132 			if (tmpPlayer && tmpPlayer->GetUniqueId() == uniqueId) {
133 				tmpSession = session_i->second;
134 				break;
135 			}
136 		}
137 
138 		++session_i;
139 	}
140 	return tmpSession;
141 }
142 
143 PlayerDataList
GetPlayerDataList() const144 SessionManager::GetPlayerDataList() const
145 {
146 	PlayerDataList playerList;
147 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
148 
149 	SessionMap::const_iterator session_i = m_sessionMap.begin();
150 	SessionMap::const_iterator session_end = m_sessionMap.end();
151 
152 	while (session_i != session_end) {
153 		// Get all players in the game.
154 		if (session_i->second->GetState() == SessionData::Game) {
155 			boost::shared_ptr<PlayerData> tmpPlayer(session_i->second->GetPlayerData());
156 			if (!tmpPlayer.get() || tmpPlayer->GetName().empty())
157 				throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0);
158 			playerList.push_back(tmpPlayer);
159 		}
160 		++session_i;
161 	}
162 	return playerList;
163 }
164 
165 PlayerDataList
GetSpectatorDataList() const166 SessionManager::GetSpectatorDataList() const
167 {
168 	PlayerDataList spectatorList;
169 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
170 
171 	SessionMap::const_iterator session_i = m_sessionMap.begin();
172 	SessionMap::const_iterator session_end = m_sessionMap.end();
173 
174 	while (session_i != session_end) {
175 		// Get all spectators of the game.
176 		if (session_i->second->GetState() == SessionData::Spectating || session_i->second->GetState() == SessionData::SpectatorWaiting) {
177 			boost::shared_ptr<PlayerData> tmpPlayer(session_i->second->GetPlayerData());
178 			if (!tmpPlayer.get() || tmpPlayer->GetName().empty())
179 				throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0);
180 			spectatorList.push_back(tmpPlayer);
181 		}
182 		++session_i;
183 	}
184 	return spectatorList;
185 }
186 
187 PlayerIdList
GetPlayerIdList(int state) const188 SessionManager::GetPlayerIdList(int state) const
189 {
190 	PlayerIdList playerList;
191 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
192 
193 	SessionMap::const_iterator session_i = m_sessionMap.begin();
194 	SessionMap::const_iterator session_end = m_sessionMap.end();
195 
196 	while (session_i != session_end) {
197 		// Get all players in the game.
198 		if ((session_i->second->GetState() & state) != 0) {
199 			playerList.push_back(session_i->second->GetPlayerData()->GetUniqueId());
200 		}
201 		++session_i;
202 	}
203 	return playerList;
204 }
205 
206 bool
IsPlayerConnected(const string & playerName) const207 SessionManager::IsPlayerConnected(const string &playerName) const
208 {
209 	bool retVal = false;
210 
211 	boost::shared_ptr<SessionData> tmpSession = GetSessionByPlayerName(playerName);
212 
213 	if (tmpSession && tmpSession->GetPlayerData())
214 		retVal = true;
215 
216 	return retVal;
217 }
218 
219 bool
IsPlayerConnected(unsigned uniqueId) const220 SessionManager::IsPlayerConnected(unsigned uniqueId) const
221 {
222 	bool retVal = false;
223 
224 	boost::shared_ptr<SessionData> tmpSession = GetSessionByUniquePlayerId(uniqueId);
225 
226 	if (tmpSession && tmpSession->GetPlayerData())
227 		retVal = true;
228 
229 	return retVal;
230 }
231 
232 bool
IsClientAddressConnected(const std::string & clientAddress) const233 SessionManager::IsClientAddressConnected(const std::string &clientAddress) const
234 {
235 	bool retVal = false;
236 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
237 
238 	SessionMap::const_iterator i = m_sessionMap.begin();
239 	SessionMap::const_iterator end = m_sessionMap.end();
240 
241 	while (i != end) {
242 		if ((*i).second->GetClientAddr() == clientAddress) {
243 			retVal = true;
244 			break;
245 		}
246 		++i;
247 	}
248 	return retVal;
249 }
250 
251 bool
IsGuestAllowedToConnect(const std::string & clientAddress) const252 SessionManager::IsGuestAllowedToConnect(const std::string &clientAddress) const
253 {
254 	bool retVal = true;
255 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
256 
257 	SessionMap::const_iterator i = m_sessionMap.begin();
258 	SessionMap::const_iterator end = m_sessionMap.end();
259 
260 	int num = 0;
261 	while (i != end) {
262 		boost::shared_ptr<PlayerData> tmpPlayer(i->second->GetPlayerData());
263 		if (tmpPlayer && tmpPlayer->GetRights() == PLAYER_RIGHTS_GUEST) {
264 			num++;
265 			if (i->second->GetClientAddr() == clientAddress) {
266 				// guest has same ip as another guest in lobby or
267 				retVal = false;
268 				break;
269 			}
270 		}
271 		++i;
272 	}
273 
274 	// Check if number of players in lobby exceeds max
275 	if (num >= SERVER_MAX_GUEST_USERS_LOBBY) retVal = false;
276 
277 	return retVal;
278 }
279 
280 void
ForEach(boost::function<void (boost::shared_ptr<SessionData>)> func)281 SessionManager::ForEach(boost::function<void (boost::shared_ptr<SessionData>)> func)
282 {
283 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
284 
285 	SessionMap::iterator i = m_sessionMap.begin();
286 	SessionMap::iterator end = m_sessionMap.end();
287 
288 	while (i != end) {
289 		SessionMap::iterator next = i;
290 		++next;
291 		func((*i).second);
292 		i = next;
293 	}
294 }
295 
296 unsigned
CountReadySessions() const297 SessionManager::CountReadySessions() const
298 {
299 	unsigned counter = 0;
300 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
301 
302 	SessionMap::const_iterator i = m_sessionMap.begin();
303 	SessionMap::const_iterator end = m_sessionMap.end();
304 
305 	while (i != end) {
306 		if ((*i).second->IsReady())
307 			++counter;
308 		++i;
309 	}
310 	return counter;
311 }
312 
313 void
ResetAllReadyFlags()314 SessionManager::ResetAllReadyFlags()
315 {
316 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
317 
318 	SessionMap::iterator i = m_sessionMap.begin();
319 	SessionMap::iterator end = m_sessionMap.end();
320 
321 	while (i != end) {
322 		(*i).second->ResetReadyFlag();
323 		++i;
324 	}
325 }
326 
327 void
Clear()328 SessionManager::Clear()
329 {
330 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
331 	SessionMap::iterator i = m_sessionMap.begin();
332 	SessionMap::iterator end = m_sessionMap.end();
333 
334 	boost::system::error_code ec;
335 	while (i != end) {
336 		// Close all raw handles.
337 		i->second->CloseSocketHandle();
338 		i->second->CloseWebSocketHandle();
339 		++i;
340 	}
341 	m_sessionMap.clear();
342 }
343 
344 unsigned
GetRawSessionCount() const345 SessionManager::GetRawSessionCount() const
346 {
347 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
348 	return (unsigned)m_sessionMap.size();
349 }
350 
351 unsigned
GetSessionCountWithState(int state) const352 SessionManager::GetSessionCountWithState(int state) const
353 {
354 	unsigned counter = 0;
355 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
356 
357 	SessionMap::const_iterator i = m_sessionMap.begin();
358 	SessionMap::const_iterator end = m_sessionMap.end();
359 
360 	while (i != end) {
361 		if ((i->second->GetState() & state) != 0)
362 			++counter;
363 		++i;
364 	}
365 	return counter;
366 }
367 
368 bool
HasSessionWithState(int state) const369 SessionManager::HasSessionWithState(int state) const
370 {
371 	bool retVal = false;
372 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
373 
374 	SessionMap::const_iterator i = m_sessionMap.begin();
375 	SessionMap::const_iterator end = m_sessionMap.end();
376 
377 	while (i != end) {
378 		if ((i->second->GetState() & state) != 0) {
379 			retVal = true;
380 			break;
381 		}
382 		++i;
383 	}
384 	return retVal;
385 }
386 
387 void
SendToAllSessions(SenderHelper & sender,boost::shared_ptr<NetPacket> packet,int state)388 SessionManager::SendToAllSessions(SenderHelper &sender, boost::shared_ptr<NetPacket> packet, int state)
389 {
390 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
391 
392 	SessionMap::iterator i = m_sessionMap.begin();
393 	SessionMap::iterator end = m_sessionMap.end();
394 
395 	while (i != end) {
396 		if (!i->second.get())
397 			throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0);
398 
399 		// Send each client (with a certain state) a copy of the packet.
400 		if ((i->second->GetState() & state) != 0)
401 			sender.Send(i->second, packet);
402 		++i;
403 	}
404 }
405 
406 void
SendLobbyMsgToAllSessions(SenderHelper & sender,boost::shared_ptr<NetPacket> packet,int state)407 SessionManager::SendLobbyMsgToAllSessions(SenderHelper &sender, boost::shared_ptr<NetPacket> packet, int state)
408 {
409 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
410 
411 	SessionMap::iterator i = m_sessionMap.begin();
412 	SessionMap::iterator end = m_sessionMap.end();
413 
414 	while (i != end) {
415 		if (!i->second.get())
416 			throw ServerException(__FILE__, __LINE__, ERR_NET_INVALID_SESSION, 0);
417 
418 		// Send each client (with a certain state) a copy of the packet.
419 		if ((i->second->GetState() & state) != 0 && i->second->WantsLobbyMsg())
420 			sender.Send(i->second, packet);
421 		++i;
422 	}
423 }
424 
425 void
SendToAllButOneSessions(SenderHelper & sender,boost::shared_ptr<NetPacket> packet,SessionId except,int state)426 SessionManager::SendToAllButOneSessions(SenderHelper &sender, boost::shared_ptr<NetPacket> packet, SessionId except, int state)
427 {
428 	boost::recursive_mutex::scoped_lock lock(m_sessionMapMutex);
429 
430 	SessionMap::iterator i = m_sessionMap.begin();
431 	SessionMap::iterator end = m_sessionMap.end();
432 
433 	while (i != end) {
434 		// Send each fully connected client but one a copy of the packet.
435 		if ((i->second->GetState() & state) != 0)
436 			if (i->first != except)
437 				sender.Send(i->second, packet);
438 		++i;
439 	}
440 }
441 
442