Leviathan  0.8.0.0
Leviathan game engine
RemoteConsole.cpp
Go to the documentation of this file.
1 // ------------------------------------ //
2 #include "RemoteConsole.h"
3 
4 #include "Connection.h"
6 #include "../TimeIncludes.h"
7 #include "NetworkRequest.h"
8 #include "NetworkResponse.h"
9 using namespace Leviathan;
10 using namespace std;
11 // ------------------------------------ //
12 DLLEXPORT Leviathan::RemoteConsole::RemoteConsole() : CloseIfNoRemoteConsole(false),
13  CanClose(false)
14 {
15 }
16 
18 }
19 // ------------------------------------ //
21 
22  GUARD_LOCK();
23  // Check awaiting connections //
24  auto timenow = Time::GetThreadSafeSteadyTimePoint();
25 
26  for(size_t i = 0; i < AwaitingConnections.size(); i++){
27  if(AwaitingConnections[i]->TimeoutTime < timenow){
28  // Time it out //
29  Logger::Get()->Warning("RemoteConsole: Remote console wait connection timed out, "
30  "token "+Convert::ToString(AwaitingConnections[i]->SessionToken));
31 
32  AwaitingConnections.erase(AwaitingConnections.begin()+i);
33  i--;
34  continue;
35  }
36  }
37 
38  // Special checks //
39  if(CloseIfNoRemoteConsole && CanClose){
40  // Send close to application if no connection (or waiting for one) //
41  if(AwaitingConnections.size() == 0 && RemoteConsoleConnections.size() == 0){
42  // Time to close //
43 
44  Logger::Get()->Info("RemoteConsole: closing the program because "
45  "CloseIfNoRemoteConsole, and no active connections");
47  }
48  }
49 
50  for(auto iter = RemoteConsoleConnections.begin(); iter != RemoteConsoleConnections.end(); )
51  {
52  if((*iter)->TerminateSession && !(*iter)->GetConnection()->IsValidForSend()){
53 
54  Logger::Get()->Info("RemoteConsole: removing kill-queued session, token: "+
55  Convert::ToString((*iter)->SessionToken));
56  iter = RemoteConsoleConnections.erase(iter);
57  } else {
58  ++iter;
59  }
60  }
61 
62 }
63 // ------------------------------------ //
65  return AwaitingConnections.size() != 0;
66 }
67 
69  const std::string &assignname /*= ""*/, bool onlylocalhost /*= false*/,
70  const MillisecondDuration &timeout /*= std::chrono::seconds(30)*/)
71 {
72  GUARD_LOCK();
73 
74  AwaitingConnections.push_back(shared_ptr<RemoteConsoleExpect>(
75  new RemoteConsoleExpect(assignname, SessionToken,
76  onlylocalhost, timeout)));
77 }
78 // ------------------------------------ //
80  std::shared_ptr<Connection> connection,
81  std::shared_ptr<NetworkRequest> request)
82 {
83  // Get data from the packet //
84  bool local = connection->IsTargetHostLocalhost();
85 
86  switch (request->GetType()) {
88  {
89  DEBUG_BREAK;
90  return true;
91  }
93  {
94  auto* opennew = static_cast<RequestRemoteConsoleOpen*>(request.get());
95 
96  int sessiontoken = opennew->SessionToken;
97 
98  // Look for a matching awaiting connection //
99  for (size_t i = 0; i < AwaitingConnections.size(); i++) {
100  if ((AwaitingConnections[i]->OnlyLocalhost && local) ||
101  !AwaitingConnections[i]->OnlyLocalhost)
102  {
103  if (AwaitingConnections[i]->SessionToken == sessiontoken) {
104  // Match found //
105  Logger::Get()->Info("RemoteConsole: matching connection request got!");
106 
107  // Add to real connections //
108  RemoteConsoleConnections.push_back(std::make_shared<RemoteConsoleSession>(
109  AwaitingConnections[i]->ConnectionName,
110  connection, AwaitingConnections[i]->SessionToken));
111 
112  // Open new, send succeed packet back //
113  connection->SendPacketToConnection(std::make_shared<ResponseNone>(
115  request->GetIDForResponse()), RECEIVE_GUARANTEE::Critical);
116 
117  AwaitingConnections.erase(AwaitingConnections.begin() + i);
118  return true;
119  }
120  }
121  }
122  }
123  default:
124  return false;
125  }
126 }
127 // ------------------------------------ //
129  std::shared_ptr<Connection> connectiontouse,
130  const std::string &connectionname, int token)
131 {
132  GUARD_LOCK();
133 
134  // Add to the expected connections //
135  AwaitingConnections.push_back(shared_ptr<RemoteConsoleExpect>(
136  new RemoteConsoleExpect(connectionname, token,
137  connectiontouse->IsTargetHostLocalhost(), std::chrono::seconds(15))));
138 
139  // Send a request that the target connects to us //
140  connectiontouse->SendPacketToConnection(std::make_shared<RequestDoRemoteConsoleOpen>(
142 }
143 // ------------------------------------ //
145  std::shared_ptr<NetworkRequest> request,
146  std::shared_ptr<Connection> connection)
147 {
148  // First check if it should be handled by CanOpenNewConnection which handless
149  // all open connection packets //
150  if(request->GetType() == NETWORK_REQUEST_TYPE::DoRemoteConsoleOpen || request->GetType() ==
152  {
153  CanOpenNewConnection(connection, request);
154  return;
155  }
156 
157  GUARD_LOCK();
158 
159  // Handle normal RemoteConsole request //
160  switch(request->GetType()){
162  {
163  // Kill connection //
164  GetRemoteConsoleSessionForConnection(guard, *connection)->KillConnection();
165  Logger::Get()->Info("RemoteConsole: closing connection due to close request");
166 
167  connection->SendPacketToConnection(std::make_shared<ResponseNone>(
169  request->GetIDForResponse()), RECEIVE_GUARANTEE::Critical);
170  return;
171  }
172  default:
173  LOG_ERROR("RemoteConsole unhandled request type");
174  }
175 
176  DEBUG_BREAK;
177 }
178 
180  std::shared_ptr<NetworkResponse> response,
181  Connection &connection, std::shared_ptr<NetworkRequest> potentialrequest)
182 {
183  // We can detect close messages //
184  switch(response->GetType()){
187  {
188  // These shouldn't be received //
189  Logger::Get()->Warning("RemoteConsole: HandleRemoteConsoleResponse: got a "
190  "packet of type remote opened/"
191  "remote closed, not expected to be received without us requesting it");
192  }
193  break;
194  default:
195  Logger::Get()->Warning("RemoteConsole: HandleRemoteConsoleResponse: got a "
196  "packet of unknown type, "
197  "maybe this should not have been passed to RemoteConsole");
198  DEBUG_BREAK;
199  }
200 }
201 // ------------------------------------ //
203  CloseIfNoRemoteConsole = state;
204 }
205 
207  Lock &guard, Connection &connection)
208 {
209  // Loop over and compare pointers //
210  for(size_t i = 0; i < RemoteConsoleConnections.size(); i++){
211  if(RemoteConsoleConnections[i]->GetConnection() == &connection){
212  // Found a matching one //
213  return RemoteConsoleConnections[i].get();
214  }
215  }
216 
217  return nullptr;
218 }
219 // ------------------------------------ //
221  return RemoteConsoleConnections.size();
222 }
223 
224 DLLEXPORT std::shared_ptr<Leviathan::Connection>
226 {
227  for (auto& connection : RemoteConsoleConnections) {
228  if (connection->ConnectionName == name) {
229 
230  return connection->CorrespondingConnection;
231  }
232  }
233 
234  return nullptr;
235 }
236 // ------------------------------------ //
238  CanClose = true;
239 }
240 // ------------------ RemoteConsoleExpect ------------------ //
241 Leviathan::RemoteConsole::RemoteConsoleExpect::RemoteConsoleExpect(const std::string &name,
242  int token, bool onlylocalhost, const MillisecondDuration &timeout) :
243  ConnectionName(name), SessionToken(token), OnlyLocalhost(onlylocalhost),
244  TimeoutTime(Time::GetThreadSafeSteadyTimePoint()+timeout)
245 {
246 
247 }
248 // ------------------ RemoteConsoleSession ------------------ //
250  // Send close request //
251  if(CorrespondingConnection->IsValidForSend()){
252 
253  CorrespondingConnection->SendPacketToConnection(std::make_shared<RequestNone>(
256  }
257 }
258 // ------------------------------------ //
260  return CorrespondingConnection.get();
261 }
262 
264  TerminateSession = true;
265 }
std::chrono::duration< int64_t, std::milli > MillisecondDuration
Definition: TimeIncludes.h:13
DLLEXPORT bool IsAwaitingConnections()
Returns true if connections are marked as awaiting.
DLLEXPORT void HandleRemoteConsoleRequestPacket(std::shared_ptr< NetworkRequest > request, std::shared_ptr< Connection > connection)
static DLLEXPORT WantedClockType::time_point GetThreadSafeSteadyTimePoint()
DLLEXPORT bool CanOpenNewConnection(std::shared_ptr< Connection > connection, std::shared_ptr< NetworkRequest > request)
Returns true if request from connection is allowed to open a remote console session.
DLLEXPORT void Info(const std::string &data) override
Definition: Logger.cpp:164
#define LOG_ERROR(x)
Definition: Define.h:90
DLLEXPORT void UpdateStatus()
Called before packets are handled.
STL namespace.
DLLEXPORT void ExpectNewConnection(int SessionToken, const std::string &assignname="", bool onlylocalhost=false, const MillisecondDuration &timeout=std::chrono::seconds(30))
DLLEXPORT void KillConnection()
Sets the connection as closing.
DLLEXPORT RemoteConsoleSession * GetRemoteConsoleSessionForConnection(Lock &guard, Connection &connection)
Gets a matching RemoteConsoleSession from Connection.
DLLEXPORT void HandleRemoteConsoleResponse(std::shared_ptr< NetworkResponse > response, Connection &connection, std::shared_ptr< NetworkRequest > potentialrequest)
The receiving side is now allowed to open a remote console with the token.
DLLEXPORT void SetCloseIfNoRemoteConsole(bool state)
Sets the remote console to close the game if there are no connections.
DLLEXPORT void MarkAsClosing()
Thread safely marks the game to close sometime.
DLLEXPORT void Warning(const std::string &data) override
Definition: Logger.cpp:190
DLLEXPORT size_t GetActiveConnectionCount()
Returns active number of connections.
DLLEXPORT std::shared_ptr< Connection > GetConnectionForRemoteConsoleSession(const std::string &name)
Gets the corresponding Connection object from a RemoteConsoleSession session indicated by name...
static std::string ToString(const T &val)
Definition: Convert.h:72
static DLLEXPORT Logger * Get()
Definition: Logger.cpp:106
static DLLEXPORT LeviathanApplication * Get()
Definition: Application.cpp:32
Class that handles a single connection to another instance.
Definition: Connection.h:105
#define DLLEXPORT
Definition: Include.h:84
The access mask controls which registered functions and classes a script sees.
Definition: GameModule.h:12
DLLEXPORT void OfferConnectionTo(std::shared_ptr< Connection > connectiontouse, const std::string &connectionname, int token)
Does everything needed to allow the client on the connection to connect to us.
#define GUARD_LOCK()
Definition: ThreadSafe.h:111
DLLEXPORT Connection * GetConnection()
std::unique_lock< std::mutex > Lock
Definition: ThreadSafe.h:18
void SetAllowClose()
Called by Engine after command line has been processed.