SEGS  0.4.2
Super Entity Game Server
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 - 2018 SEGS Team (see Authors.txt)
5  * This software is licensed! (See License.txt 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 
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  ACE_DEBUG ((LM_WARNING,ACE_TEXT ("(%P|%t) create_cookie still needs a good algorithm.0x%08x\n"),res));
62  return (uint32_t)res;
63  }
64 
65 public:
67  {
68  return m_active_sessions.begin();
69  }
71  {
72  return m_active_sessions.end();
73  }
74  civClients begin() const
75  {
76  return m_active_sessions.cbegin();
77  }
78  civClients end() const
79  {
80  return m_active_sessions.cend();
81  }
82  std::mutex &store_lock()
83  {
84  return m_store_mutex;
85  }
86  std::mutex &reap_lock()
87  {
88  return m_reaping_mutex;
89  }
90  SESSION_CLASS &create_session(uint64_t token)
91  {
92  assert(m_token_to_session.find(token)==m_token_to_session.end());
93  return m_token_to_session[token];
94  }
95  uint64_t token_for_id(uint32_t id) const
96  {
97  auto iter = m_id_to_token.find(id);
98  if(iter==m_id_to_token.end())
99  return 0;
100  return iter->second;
101  }
102  void setTokenForId(uint32_t id,uint64_t token)
103  {
104  m_id_to_token[id] = token;
105  }
106  bool has_session_for(uint64_t token) const
107  {
108  return m_token_to_session.find(token)!=m_token_to_session.end();
109  }
110  SESSION_CLASS &session_from_token(uint64_t token)
111  {
112  auto iter = m_token_to_session.find(token);
113  assert(iter != m_token_to_session.end());
114  return iter->second;
115  }
116  SESSION_CLASS &session_from_event(SEGSEvent *ev)
117  {
118  assert(dynamic_cast<LinkBase *>(ev->src())!=nullptr); // make sure the event source is a Link
119  LinkBase * lnk = (LinkBase *)ev->src();
120  auto iter = m_token_to_session.find(lnk->session_token());
121  assert(iter!=m_token_to_session.end());
122  SESSION_CLASS &session(iter->second);
123  assert(session.link()==lnk);
124  return session;
125  }
126 
127  SESSION_CLASS &session_from_event(InternalEvent *ev)
128  {
129  auto iter = m_token_to_session.find(ev->session_token());
130  assert(iter != m_token_to_session.end());
131  return iter->second;
132  }
133  uint32_t expect_client_session(uint64_t token, const ACE_INET_Addr &from, uint64_t id)
134  {
135  uint32_t cook = create_cookie(from, id);
136  for (ExpectClientInfo sess : m_session_expecting_clients)
137  {
138  // if we already expect this client
139  if (sess.m_cookie == cook)
140  {
141  assert(false);
142  // return pregenerated cookie
143  return cook;
144  }
145  }
146  m_session_expecting_clients.emplace_back(ExpectClientInfo{cook, ACE_OS::gettimeofday(), token});
147  return cook;
148  }
149  // used to recover assigned cookie from session
150  uint32_t get_cookie_for_session(uint64_t token)
151  {
152  for (ExpectClientInfo sess : m_session_expecting_clients)
153  {
154  if(sess.m_session_token==token)
155  return sess.m_cookie;
156  }
157  return 0;
158  }
159  void session_link_lost(uint64_t token)
160  {
161  SESSION_CLASS &session(session_from_token(token));
162  remove_from_active_sessions(&session);
163  for (size_t idx = 0, total = m_session_expecting_clients.size(); idx < total; ++idx)
164  {
165  if (m_session_expecting_clients[idx].m_session_token == token)
166  {
168  m_session_expecting_clients.pop_back();
169  break;
170  }
171  }
172  session.link(nullptr);
173  }
174  void remove_by_token(uint64_t token, uint32_t id)
175  {
176  m_id_to_token.erase(id);
177  m_token_to_session.erase(token);
178  }
179  uint64_t connected_client(uint32_t cookie)
180  {
181  for (size_t idx = 0, total = m_session_expecting_clients.size(); idx < total; ++idx)
182  {
183  if (m_session_expecting_clients[idx].m_cookie == cookie)
184  {
185  uint64_t expected_in_session = m_session_expecting_clients[idx].m_session_token;
187  m_session_expecting_clients.pop_back();
188  return expected_in_session;
189  }
190  }
191  return ~0U;
192  }
193  void remove_from_active_sessions(SESSION_CLASS *cl)
194  {
195  for(size_t idx=0,total=m_active_sessions.size(); idx<total; ++idx)
196  {
197  if(m_active_sessions[idx]==cl)
198  {
199  std::swap(m_active_sessions[idx],m_active_sessions.back());
200  m_active_sessions.pop_back();
201  return;
202  }
203  }
204  assert(false);
205  }
206  void add_to_active_sessions(SESSION_CLASS *cl)
207  {
208  for(size_t idx=0,total=m_active_sessions.size(); idx<total; ++idx)
209  {
210  if(m_active_sessions[idx]==cl)
211  return;
212  }
213  m_active_sessions.emplace_back(cl);
214  }
215  bool isActive(SESSION_CLASS *c) const
216  {
217  return std::find(m_active_sessions.begin(),m_active_sessions.end(),c)!=m_active_sessions.end();
218  }
219  size_t num_sessions() const
220  {
221  return m_token_to_session.size();
222  }
223  void create_reaping_timer(EventProcessor *tgt, uint32_t id, ACE_Time_Value interval)
224  {
225  m_session_reaper_timer.reset(new SEGSTimer(tgt, (void *)id, interval, false));
226  }
227  void mark_session_for_reaping(SESSION_CLASS *sess, uint64_t token)
228  {
229  m_session_ready_for_reaping.emplace_back(WaitingSession{ACE_OS::gettimeofday(), sess, token});
230  }
231  void locked_mark_session_for_reaping(SESSION_CLASS *sess, uint64_t token)
232  {
233  MTGuard guard(reap_lock());
234  mark_session_for_reaping(sess,token);
235  }
236 
237  void unmark_session_for_reaping(SESSION_CLASS *sess)
238  {
239  for (size_t idx = 0, total = m_session_ready_for_reaping.size(); idx < total; ++idx)
240  {
241  if (m_session_ready_for_reaping[idx].m_session == sess)
242  {
244  m_session_ready_for_reaping.pop_back();
245  break;
246  }
247  }
248  }
249  void locked_unmark_session_for_reaping(SESSION_CLASS *sess)
250  {
251  MTGuard guard(reap_lock());
253  }
254  void reap_stale_links(const char *name, ACE_Time_Value link_is_stale_if_disconnected_for,
255  std::function<void(uint64_t token)> reap_callback = [](uint64_t) {})
256  {
257  ACE_Time_Value time_now = ACE_OS::gettimeofday();
258  for (size_t idx = 0, total = m_session_ready_for_reaping.size(); idx < total; ++idx)
259  {
260  WaitingSession &waiting_session(m_session_ready_for_reaping[idx]);
261  if (time_now - waiting_session.m_waiting_since < link_is_stale_if_disconnected_for)
262  continue;
263  if (waiting_session.m_session->link() == nullptr || waiting_session.m_session->is_temporary() ) // trully disconnected
264  {
265  qDebug() << name << "Reaping stale link" << intptr_t(waiting_session.m_session);
266  reap_callback(waiting_session.m_session_token);
267  if(waiting_session.m_session->link()) // it's a temporary session
268  {
269  // telling the temporary link to close.
270  waiting_session.m_session->link()->putq(SEGSEvent::s_ev_finish.shallow_copy());
271  }
272  // we destroy the session object
273  remove_by_token(waiting_session.m_session_token, waiting_session.m_session->auth_id());
275  m_session_ready_for_reaping.pop_back();
276  total--; // update the total size
277  }
278  else
279  {
280  // the session still has a link 'active', re-schedule the check
281  waiting_session.m_waiting_since = time_now;
282  }
283  }
284  }
285  SESSION_CLASS *create_or_reuse_session_for(uint64_t token)
286  {
287  SESSION_CLASS * sess;
288  MTGuard guard(reap_lock());
289 
290  auto iter = m_token_to_session.find(token);
291  if (iter != m_token_to_session.end())
292  {
293  sess = &iter->second;
295  qDebug() << "Existing client session reused";
296  sess->reset();
297  } else
298  sess = &create_session(token);
299  return sess;
300  }
301 };
302 
304 template <class SESSION_CLASS>
306 {
307  SESSION_CLASS *m_protectee;
308  uint64_t m_token;
310  ReaperProtection(SESSION_CLASS *session,uint64_t token,ClientSessionStore<SESSION_CLASS> &store) :
311  m_protectee(session),m_token(token),m_store(store)
312  {
313  store.unmark_session_for_reaping(session);
314  m_protectee=session;
315  }
317  {
318  if(m_protectee)
319  {
320  typename ClientSessionStore<SESSION_CLASS>::MTGuard guard(m_store.reap_lock());
321  m_store.mark_session_for_reaping(m_protectee,m_token);
322  }
323  }
324  void protectee_moved() { m_protectee = nullptr; }
325 };
typename vClients::const_iterator civClients
Definition: ClientManager.h:33
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:305
size_t num_sessions() const
Definition: ClientManager.h:219
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:249
uint64_t m_token
Definition: ClientManager.h:308
uint64_t token_for_id(uint32_t id) const
Definition: ClientManager.h:95
Definition: SEGSEvent.h:32
uint64_t connected_client(uint32_t cookie)
Definition: ClientManager.h:179
Definition: ClientManager.h:38
ClientSessionStore< SESSION_CLASS > & m_store
Definition: ClientManager.h:309
typename vClients::iterator ivClients
Definition: ClientManager.h:32
void session_token(uint64_t token)
Definition: InternalEvents.h:45
SESSION_CLASS & session_from_event(InternalEvent *ev)
Definition: ClientManager.h:127
Definition: ClientManager.h:27
std::vector< WaitingSession > m_session_ready_for_reaping
Definition: ClientManager.h:56
civClients begin() const
Definition: ClientManager.h:74
std::lock_guard< std::mutex > MTGuard
Definition: ClientManager.h:30
void remove_from_active_sessions(SESSION_CLASS *cl)
Definition: ClientManager.h:193
SESSION_CLASS & session_from_event(SEGSEvent *ev)
Definition: ClientManager.h:116
void unmark_session_for_reaping(SESSION_CLASS *sess)
Definition: ClientManager.h:237
void add_to_active_sessions(SESSION_CLASS *cl)
Definition: ClientManager.h:206
void locked_mark_session_for_reaping(SESSION_CLASS *sess, uint64_t token)
Definition: ClientManager.h:231
void session_link_lost(uint64_t token)
Definition: ClientManager.h:159
bool has_session_for(uint64_t token) const
Definition: ClientManager.h:106
void create_reaping_timer(EventProcessor *tgt, uint32_t id, ACE_Time_Value interval)
Definition: ClientManager.h:223
ivClients begin()
Definition: ClientManager.h:66
ReaperProtection(SESSION_CLASS *session, uint64_t token, ClientSessionStore< SESSION_CLASS > &store)
Definition: ClientManager.h:310
static SEGSEvent s_ev_finish
Definition: SEGSEvent.h:66
SESSION_CLASS * m_protectee
Definition: ClientManager.h:307
~ReaperProtection()
Definition: ClientManager.h:316
bool isActive(SESSION_CLASS *c) const
Definition: ClientManager.h:215
Definition: ILink.h:14
ivClients end()
Definition: ClientManager.h:70
uint32_t m_cookie
Definition: ClientManager.h:40
void protectee_moved()
Definition: ClientManager.h:324
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:227
std::mutex & reap_lock()
Definition: ClientManager.h:86
uint64_t m_session_token
Definition: ClientManager.h:42
SESSION_CLASS & session_from_token(uint64_t token)
Definition: ClientManager.h:110
Definition: InternalEvents.h:39
uint32_t get_cookie_for_session(uint64_t token)
Definition: ClientManager.h:150
uint64_t session_token() const
Definition: ILink.h:20
uint32_t expect_client_session(uint64_t token, const ACE_INET_Addr &from, uint64_t id)
Definition: ClientManager.h:133
std::unordered_map< uint32_t, uint64_t > m_id_to_token
Definition: ClientManager.h:54
Definition: EventProcessor.h:13
uint64_t m_session_token
Definition: ClientManager.h:51
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
void remove_by_token(uint64_t token, uint32_t id)
Definition: ClientManager.h:174
std::unique_ptr< SEGSTimer > m_session_reaper_timer
Definition: ClientManager.h:35
SESSION_CLASS * create_or_reuse_session_for(uint64_t token)
Definition: ClientManager.h:285
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:254
std::mutex m_reaping_mutex
Definition: ClientManager.h:37
SESSION_CLASS * m_session
Definition: ClientManager.h:50
std::mutex & store_lock()
Definition: ClientManager.h:82
void setTokenForId(uint32_t id, uint64_t token)
Definition: ClientManager.h:102
civClients end() const
Definition: ClientManager.h:78
void src(EventProcessor *ev_src)
Definition: SEGSEvent.h:61
SESSION_CLASS & create_session(uint64_t token)
Definition: ClientManager.h:90