SEGS  0.6.1-develop [d2cac982]
Super Entity Game Server
ClientManager.h
Go to the documentation of this file.
1 /*
2  * SEGS - Super Entity Game Server
3  * http://www.segs.io/
4  * Copyright (c) 2006 - 2019 SEGS Team (see AUTHORS.md)
5  * This software is licensed under the terms of the 3-clause BSD License. See LICENSE.md for details.
6  */
7 
8 #pragma once
10 #include "InternalEvents.h"
11 #include "SEGSEvent.h"
12 #include "SEGSTimer.h"
13 
14 #include <ace/OS_NS_time.h>
15 
16 #include <QDebug>
17 #include <thread>
18 #include <mutex>
19 #include <memory>
20 #include <unordered_map>
21 #include <vector>
22 #include <cassert>
23 #include <cinttypes>
24 
25 // TODO: consider storing all sessions in vector, and convert m_session_store to token->index map
26 template <class SESSION_CLASS>
28 {
29 public:
30 using MTGuard = std::lock_guard<std::mutex>;
31 using vClients = std::vector<SESSION_CLASS *>;
32 using ivClients = typename vClients::iterator;
33 using civClients = typename vClients::const_iterator;
34 protected:
35  std::unique_ptr<SEGSTimer> m_session_reaper_timer;
36 mutable std::mutex m_store_mutex;
37  std::mutex m_reaping_mutex;
39  {
40  uint32_t m_cookie;
41  ACE_Time_Value m_expected_since;
42  uint64_t m_session_token;
43  };
48  {
49  ACE_Time_Value m_waiting_since;
50  SESSION_CLASS *m_session;
51  uint64_t m_session_token;
52  };
53  std::unordered_map<uint64_t,SESSION_CLASS> m_token_to_session;
54  std::unordered_map<uint32_t,uint64_t> m_id_to_token;
55  std::vector<ExpectClientInfo> m_session_expecting_clients;
56  std::vector<WaitingSession> m_session_ready_for_reaping;
58  uint32_t create_cookie(const ACE_INET_Addr &from,uint64_t id)
59  {
60  uint64_t res = ((from.hash()+id)&0xFFFFFFFF)^(id>>32);
61  qWarning("Create_cookie still needs a good algorithm. 0x%" PRIx64, res);
62  return (uint32_t)res;
63  }
64 
65 public:
67  {
68  return m_active_sessions;
69  }
70 
72  {
73  return m_active_sessions.begin();
74  }
76  {
77  return m_active_sessions.end();
78  }
79  civClients begin() const
80  {
81  return m_active_sessions.cbegin();
82  }
83  civClients end() const
84  {
85  return m_active_sessions.cend();
86  }
87  std::mutex &store_lock()
88  {
89  return m_store_mutex;
90  }
91  std::mutex &reap_lock()
92  {
93  return m_reaping_mutex;
94  }
95  SESSION_CLASS &create_session(uint64_t token)
96  {
97  assert(m_token_to_session.find(token)==m_token_to_session.end());
98  return m_token_to_session[token];
99  }
100  uint64_t token_for_id(uint32_t id) const
101  {
102  auto iter = m_id_to_token.find(id);
103  if(iter==m_id_to_token.end())
104  return 0;
105  return iter->second;
106  }
107  void setTokenForId(uint32_t id,uint64_t token)
108  {
109  m_id_to_token[id] = token;
110  }
111  bool has_session_for(uint64_t token) const
112  {
113  return m_token_to_session.find(token)!=m_token_to_session.end();
114  }
115  SESSION_CLASS &session_from_token(uint64_t token)
116  {
117  auto iter = m_token_to_session.find(token);
118  assert(iter != m_token_to_session.end());
119  return iter->second;
120  }
122  {
123  assert(dynamic_cast<LinkBase *>(ev->src())!=nullptr); // make sure the event source is a Link
124  LinkBase * lnk = (LinkBase *)ev->src();
125  auto iter = m_token_to_session.find(lnk->session_token());
126  assert(iter!=m_token_to_session.end());
127  SESSION_CLASS &session(iter->second);
128  assert(session.link()==lnk);
129  return session;
130  }
131 
133  {
134  auto iter = m_token_to_session.find(ev->session_token());
135  assert(iter != m_token_to_session.end());
136  return iter->second;
137  }
138  uint32_t expect_client_session(uint64_t token, const ACE_INET_Addr &from, uint64_t id)
139  {
140  uint32_t cook = create_cookie(from, id);
141  for (ExpectClientInfo sess : m_session_expecting_clients)
142  {
143  // if we already expect this client
144  if(sess.m_cookie == cook)
145  {
146  // return pregenerated cookie
147  return cook;
148  }
149  }
150  m_session_expecting_clients.emplace_back(ExpectClientInfo{cook, ACE_OS::gettimeofday(), token});
151  return cook;
152  }
153  // used to recover assigned cookie from session
154  uint32_t get_cookie_for_session(uint64_t token)
155  {
156  for (ExpectClientInfo sess : m_session_expecting_clients)
157  {
158  if(sess.m_session_token==token)
159  return sess.m_cookie;
160  }
161  return 0;
162  }
163  void session_link_lost(uint64_t token)
164  {
165  SESSION_CLASS &session(session_from_token(token));
166  remove_from_active_sessions(&session);
167  for (size_t idx = 0, total = m_session_expecting_clients.size(); idx < total; ++idx)
168  {
169  if(m_session_expecting_clients[idx].m_session_token == token)
170  {
171  std::swap(m_session_expecting_clients[idx], m_session_expecting_clients.back());
172  m_session_expecting_clients.pop_back();
173  break;
174  }
175  }
176  session.link(nullptr);
177  }
178  void remove_by_token(uint64_t token, uint32_t id)
179  {
180  m_id_to_token.erase(id);
181  m_token_to_session.erase(token);
182  }
183  uint64_t connected_client(uint32_t cookie)
184  {
185  for (size_t idx = 0, total = m_session_expecting_clients.size(); idx < total; ++idx)
186  {
187  if(m_session_expecting_clients[idx].m_cookie == cookie)
188  {
189  uint64_t expected_in_session = m_session_expecting_clients[idx].m_session_token;
190  std::swap(m_session_expecting_clients[idx], m_session_expecting_clients.back());
191  m_session_expecting_clients.pop_back();
192  return expected_in_session;
193  }
194  }
195  return ~0U;
196  }
197  void remove_from_active_sessions(SESSION_CLASS *cl)
198  {
199  for(size_t idx=0,total=m_active_sessions.size(); idx<total; ++idx)
200  {
201  if(m_active_sessions[idx]==cl)
202  {
203  std::swap(m_active_sessions[idx],m_active_sessions.back());
204  m_active_sessions.pop_back();
205  return;
206  }
207  }
208  assert(false);
209  }
210  void add_to_active_sessions(SESSION_CLASS *cl)
211  {
212  for(size_t idx=0,total=m_active_sessions.size(); idx<total; ++idx)
213  {
214  if(m_active_sessions[idx]==cl)
215  return;
216  }
217  m_active_sessions.emplace_back(cl);
218  }
219  bool isActive(SESSION_CLASS *c) const
220  {
221  return std::find(m_active_sessions.begin(),m_active_sessions.end(),c)!=m_active_sessions.end();
222  }
223  size_t num_sessions() const
224  {
225  return m_token_to_session.size();
226  }
227  void create_reaping_timer(EventProcessor *tgt, uint32_t id, ACE_Time_Value interval)
228  {
229  m_session_reaper_timer.reset(new SEGSTimer(tgt, id, interval, false));
230  }
231  void mark_session_for_reaping(SESSION_CLASS *sess, uint64_t token)
232  {
233  m_session_ready_for_reaping.emplace_back(WaitingSession{ACE_OS::gettimeofday(), sess, token});
234  }
235  void locked_mark_session_for_reaping(SESSION_CLASS *sess, uint64_t token)
236  {
237  MTGuard guard(reap_lock());
238  mark_session_for_reaping(sess,token);
239  }
240 
241  void unmark_session_for_reaping(SESSION_CLASS *sess)
242  {
243  for (size_t idx = 0, total = m_session_ready_for_reaping.size(); idx < total; ++idx)
244  {
245  if(m_session_ready_for_reaping[idx].m_session == sess)
246  {
247  std::swap(m_session_ready_for_reaping[idx], m_session_ready_for_reaping.back());
248  m_session_ready_for_reaping.pop_back();
249  break;
250  }
251  }
252  }
253  void locked_unmark_session_for_reaping(SESSION_CLASS *sess)
254  {
255  MTGuard guard(reap_lock());
257  }
258  void reap_stale_links(const char *name, ACE_Time_Value link_is_stale_if_disconnected_for,
259  std::function<void(uint64_t token)> reap_callback = [](uint64_t) {})
260  {
261  ACE_Time_Value time_now = ACE_OS::gettimeofday();
262  for (size_t idx = 0, total = m_session_ready_for_reaping.size(); idx < total; ++idx)
263  {
264  WaitingSession &waiting_session(m_session_ready_for_reaping[idx]);
265  if(time_now - waiting_session.m_waiting_since < link_is_stale_if_disconnected_for)
266  continue;
267  if(waiting_session.m_session->link() == nullptr || waiting_session.m_session->is_temporary() ) // trully disconnected
268  {
269  qDebug() << name << "Reaping stale link" << intptr_t(waiting_session.m_session);
270  reap_callback(waiting_session.m_session_token);
271  if(waiting_session.m_session->link()) // it's a temporary session
272  {
273  // telling the temporary link to close.
274  waiting_session.m_session->link()->putq(SEGSEvents::Finish::s_instance->shallow_copy());
275  }
276  // we destroy the session object
277  remove_by_token(waiting_session.m_session_token, waiting_session.m_session->auth_id());
278  std::swap(m_session_ready_for_reaping[idx], m_session_ready_for_reaping.back());
279  m_session_ready_for_reaping.pop_back();
280  total--; // update the total size
281  }
282  else
283  {
284  // the session still has a link 'active', re-schedule the check
285  waiting_session.m_waiting_since = time_now;
286  }
287  }
288  }
289  SESSION_CLASS *create_or_reuse_session_for(uint64_t token)
290  {
291  SESSION_CLASS * sess;
292  MTGuard guard(reap_lock());
293 
294  auto iter = m_token_to_session.find(token);
295  if(iter != m_token_to_session.end())
296  {
297  sess = &iter->second;
299  qDebug() << "Existing client session reused";
300  sess->reset();
301  } else
302  sess = &create_session(token);
303  return sess;
304  }
305 };
306 
308 template <class SESSION_CLASS>
310 {
311  SESSION_CLASS *m_protectee;
312  uint64_t m_token;
314  ReaperProtection(SESSION_CLASS *session,uint64_t token,ClientSessionStore<SESSION_CLASS> &store) :
315  m_protectee(session),m_token(token),m_store(store)
316  {
317  store.unmark_session_for_reaping(session);
318  m_protectee=session;
319  }
321  {
322  if(m_protectee)
323  {
324  typename ClientSessionStore<SESSION_CLASS>::MTGuard guard(m_store.reap_lock());
325  m_store.mark_session_for_reaping(m_protectee,m_token);
326  }
327  }
328  void protectee_moved() { m_protectee = nullptr; }
329 };
size_t num_sessions() const
Definition: ClientManager.h:223
Definition: InternalEvents.h:43
typename vClients::const_iterator civClients
Definition: ClientManager.h:33
civClients begin() const
Definition: ClientManager.h:79
uint32_t create_cookie(const ACE_INET_Addr &from, uint64_t id)
Definition: ClientManager.h:58
Instances of SEGSTimer class are used to schedule events in the future.
Definition: SEGSTimer.h:18
Definition: ClientManager.h:309
bool has_session_for(uint64_t token) const
Definition: ClientManager.h:111
std::unordered_map< uint64_t, SESSION_CLASS > m_token_to_session
Definition: ClientManager.h:53
void locked_unmark_session_for_reaping(SESSION_CLASS *sess)
Definition: ClientManager.h:253
uint64_t m_token
Definition: ClientManager.h:312
bool isActive(SESSION_CLASS *c) const
Definition: ClientManager.h:219
uint64_t session_token() const
Definition: ILink.h:21
uint64_t connected_client(uint32_t cookie)
Definition: ClientManager.h:183
Definition: ClientManager.h:38
ClientSessionStore< SESSION_CLASS > & m_store
Definition: ClientManager.h:313
typename vClients::iterator ivClients
Definition: ClientManager.h:32
SESSION_CLASS & session_from_event(SEGSEvents::Event *ev)
Definition: ClientManager.h:121
Definition: SEGSEvent.h:35
Definition: ClientManager.h:27
std::vector< WaitingSession > m_session_ready_for_reaping
Definition: ClientManager.h:56
std::lock_guard< std::mutex > MTGuard
Definition: ClientManager.h:30
void remove_from_active_sessions(SESSION_CLASS *cl)
Definition: ClientManager.h:197
void unmark_session_for_reaping(SESSION_CLASS *sess)
Definition: ClientManager.h:241
void add_to_active_sessions(SESSION_CLASS *cl)
Definition: ClientManager.h:210
void locked_mark_session_for_reaping(SESSION_CLASS *sess, uint64_t token)
Definition: ClientManager.h:235
void src(EventSrc *ev_src)
Definition: SEGSEvent.h:64
static Finish * s_instance
Definition: SEGSEvent.h:96
void session_link_lost(uint64_t token)
Definition: ClientManager.h:163
void create_reaping_timer(EventProcessor *tgt, uint32_t id, ACE_Time_Value interval)
Definition: ClientManager.h:227
ivClients begin()
Definition: ClientManager.h:71
ReaperProtection(SESSION_CLASS *session, uint64_t token, ClientSessionStore< SESSION_CLASS > &store)
Definition: ClientManager.h:314
SESSION_CLASS * m_protectee
Definition: ClientManager.h:311
~ReaperProtection()
Definition: ClientManager.h:320
Definition: ILink.h:14
ivClients end()
Definition: ClientManager.h:75
void reap_stale_links(const char *name, ACE_Time_Value link_is_stale_if_disconnected_for, std::function< void(uint64_t token)> reap_callback=[](uint64_t) {})
Definition: ClientManager.h:258
uint32_t m_cookie
Definition: ClientManager.h:40
void protectee_moved()
Definition: ClientManager.h:328
std::vector< ExpectClientInfo > m_session_expecting_clients
Definition: ClientManager.h:55
ACE_Time_Value m_expected_since
Definition: ClientManager.h:41
ACE_Time_Value m_waiting_since
Definition: ClientManager.h:49
std::mutex m_store_mutex
Definition: ClientManager.h:36
void mark_session_for_reaping(SESSION_CLASS *sess, uint64_t token)
Definition: ClientManager.h:231
std::mutex & reap_lock()
Definition: ClientManager.h:91
uint64_t m_session_token
Definition: ClientManager.h:42
SESSION_CLASS & session_from_token(uint64_t token)
Definition: ClientManager.h:115
uint32_t get_cookie_for_session(uint64_t token)
Definition: ClientManager.h:154
void session_token(uint64_t token)
Definition: InternalEvents.h:49
uint32_t expect_client_session(uint64_t token, const ACE_INET_Addr &from, uint64_t id)
Definition: ClientManager.h:138
std::unordered_map< uint32_t, uint64_t > m_id_to_token
Definition: ClientManager.h:54
Definition: EventProcessor.h:22
uint64_t m_session_token
Definition: ClientManager.h:51
SESSION_CLASS & session_from_event(SEGSEvents::InternalEvent *ev)
Definition: ClientManager.h:132
The WaitingSession struct is used to store sessions without active connections in any server...
Definition: ClientManager.h:47
vClients m_active_sessions
Definition: ClientManager.h:57
std::vector< GameSession *> vClients
Definition: ClientManager.h:31
uint64_t token_for_id(uint32_t id) const
Definition: ClientManager.h:100
void remove_by_token(uint64_t token, uint32_t id)
Definition: ClientManager.h:178
std::unique_ptr< SEGSTimer > m_session_reaper_timer
Definition: ClientManager.h:35
civClients end() const
Definition: ClientManager.h:83
SESSION_CLASS * create_or_reuse_session_for(uint64_t token)
Definition: ClientManager.h:289
std::mutex m_reaping_mutex
Definition: ClientManager.h:37
SESSION_CLASS * m_session
Definition: ClientManager.h:50
std::mutex & store_lock()
Definition: ClientManager.h:87
void setTokenForId(uint32_t id, uint64_t token)
Definition: ClientManager.h:107
const vClients & get_active_sessions()
Definition: ClientManager.h:66
SESSION_CLASS & create_session(uint64_t token)
Definition: ClientManager.h:95