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