RemoteDebuggerBridge.cc 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #ifndef _REMOTE_DEBUGGER_BRIDGE_H_
  23. #include "debug/remote/RemoteDebuggerBridge.h"
  24. #endif
  25. #ifndef _REMOTE_DEBUGGER_BASE_H_
  26. #include "debug/remote/RemoteDebuggerBase.h"
  27. #endif
  28. #ifndef _SIMBASE_H_
  29. #include "sim/simBase.h"
  30. #endif
  31. #ifndef _STRINGUNIT_H_
  32. #include "string/stringUnit.h"
  33. #endif
  34. #ifndef _EVENT_H_
  35. #include "platform/event.h"
  36. #endif
  37. // Script bindings.
  38. #include "debug/remote/RemoteDebuggerBridge_ScriptBinding.h"
  39. //-----------------------------------------------------------------------------
  40. static S32 DebuggerVersion = 0;
  41. static S32 DebuggerPort = 0;
  42. static StringTableEntry DebuggerPassword = NULL;
  43. static NetSocket ServerSocket = NetSocket::INVALID;
  44. static NetSocket ClientSocket = NetSocket::INVALID;
  45. static RemoteDebuggerBridge::ConnectionState BridgeState = RemoteDebuggerBridge::Closed;
  46. //-----------------------------------------------------------------------------
  47. void RemoteDebuggerBridge::processCommandLine( S32 argc, const char **argv )
  48. {
  49. // Find if the remote debugger is specified on the command-line.
  50. for( S32 argIndex = 0; argIndex < argc; ++argIndex )
  51. {
  52. // Fetch argument.
  53. const char* pArg = argv[argIndex];
  54. // Skip if this is this the remote debugger argument.
  55. if ( dStrnicmp( pArg, REMOTE_DEBUGGER_COMMAND_LINE_ARG, dStrlen( REMOTE_DEBUGGER_COMMAND_LINE_ARG ) ) != 0 )
  56. continue;
  57. // Fetch debugger argument count.
  58. const U32 debuggerArgumentCount = StringUnit::getUnitCount( pArg, REMOTE_DEBUGGER_COMMAND_LINE_ARG_SEPARATOR );
  59. // Are there enough arguments for opening the remote bridge?
  60. if ( debuggerArgumentCount != 3 && debuggerArgumentCount != 4 )
  61. {
  62. // No, so warn.
  63. Con::warnf( "Found the debugger command-line of '%s' however invalid arguments were specified. Format is '%s%s<Version>%s<Port>[%s<Password>]'.",
  64. pArg,
  65. REMOTE_DEBUGGER_COMMAND_LINE_ARG,
  66. REMOTE_DEBUGGER_COMMAND_LINE_ARG_SEPARATOR,
  67. REMOTE_DEBUGGER_COMMAND_LINE_ARG_SEPARATOR,
  68. REMOTE_DEBUGGER_COMMAND_LINE_ARG_SEPARATOR );
  69. return;
  70. }
  71. // Fetch debugger version.
  72. const S32 debuggerVersion = dAtoi( StringUnit::getUnit( pArg, 1, REMOTE_DEBUGGER_COMMAND_LINE_ARG_SEPARATOR ) );
  73. // Fetch port.
  74. const S32 port = dAtoi( StringUnit::getUnit( pArg, 2, REMOTE_DEBUGGER_COMMAND_LINE_ARG_SEPARATOR ) );
  75. // Fetch password.
  76. const char* pPassword = debuggerArgumentCount == 4 ? StringUnit::getUnit( pArg, 3, REMOTE_DEBUGGER_COMMAND_LINE_ARG_SEPARATOR ) : "";
  77. // Open remote debugger with port and password.
  78. RemoteDebuggerBridge::open( debuggerVersion, port, pPassword );
  79. }
  80. }
  81. //-----------------------------------------------------------------------------
  82. bool RemoteDebuggerBridge::open( const S32 debuggerVersion, const S32 port, const char* pPassword )
  83. {
  84. // Sanity!
  85. AssertFatal( debuggerVersion > 0, "Debugger version must be >0 ." );
  86. AssertFatal( port > 0, "Debugger port must be >0." );
  87. AssertFatal( pPassword != NULL, "Debugger password cannot be NULL." );
  88. // Is the bridge closed?
  89. if ( BridgeState != RemoteDebuggerBridge::Closed )
  90. {
  91. // Yes, so warn.
  92. Con::warnf( "Cannot start remote debugger sessions as it is already started." );
  93. return false;
  94. }
  95. // Is the debugger version valid?
  96. if ( debuggerVersion < 1 )
  97. {
  98. // No, so warn.
  99. Con::warnf( "Invalid debugger version '%d'.", debuggerVersion );
  100. return false;
  101. }
  102. // Format debugger version.
  103. char debuggerClassBuffer[64];
  104. dSprintf( debuggerClassBuffer, sizeof(debuggerClassBuffer), "RemoteDebugger%d", debuggerVersion );
  105. // Find debugger.
  106. AbstractClassRep* pDebuggerRep = AbstractClassRep::findClassRep( debuggerClassBuffer );
  107. // Did we find the debugger?
  108. if ( pDebuggerRep == NULL )
  109. {
  110. // No, so warn.
  111. Con::warnf( "Failed to find debugger version '%d' (%s).", debuggerVersion, debuggerClassBuffer );
  112. return false;
  113. }
  114. // Create debugger.
  115. RemoteDebuggerBase* pRemoteDebugger = dynamic_cast<RemoteDebuggerBase*>( pDebuggerRep->create() );
  116. // Did we create the debugger?
  117. if ( pRemoteDebugger == NULL )
  118. {
  119. // No, so warn.
  120. Con::warnf( "Failed to create debugger version '%d' (%s).", debuggerVersion, debuggerClassBuffer );
  121. return false;
  122. }
  123. // Register the debugger.
  124. if ( !pRemoteDebugger->registerObject( REMOTE_DEBUGGER_NAME ) )
  125. {
  126. // Failed to register the debugger so warn.
  127. Con::warnf( "Failed to register debugger version '%d' (%s).", debuggerVersion, debuggerClassBuffer );
  128. // Delete the remove debugger.
  129. pRemoteDebugger->deleteObject();
  130. pRemoteDebugger = NULL;
  131. return false;
  132. }
  133. // Set debugger, its version, port and password.
  134. DebuggerVersion = debuggerVersion;
  135. DebuggerPort = port;
  136. DebuggerPassword = StringTable->insert( pPassword );
  137. // Set bridge state.
  138. BridgeState = Open;
  139. // Open the server socket.
  140. ServerSocket = Net::openSocket();
  141. // Did we get a valid server socket?
  142. if ( ServerSocket == NetSocket::INVALID )
  143. {
  144. // No, so warn.
  145. Con::warnf( "Could not open a remote debugger server socket. " );
  146. return false;
  147. }
  148. NetAddress address;
  149. Net::getIdealListenAddress(&address);
  150. address.port = DebuggerPort;
  151. // Start the server listening.
  152. Net::bindAddress( address, ServerSocket);
  153. Net::listen( ServerSocket, 4 );
  154. Net::setBlocking( ServerSocket, false );
  155. // Wait for the client connection.
  156. WaitForClientConnection();
  157. // Set debugger client socket.
  158. // NOTE: This signals the debugger that it can now start receiving commands from the specified socket.
  159. pRemoteDebugger->mClientSocket = ClientSocket;
  160. // Wait for the client log-in.
  161. WaitForClientLogin();
  162. return true;
  163. }
  164. //-----------------------------------------------------------------------------
  165. bool RemoteDebuggerBridge::close( void )
  166. {
  167. return false;
  168. }
  169. //-----------------------------------------------------------------------------
  170. RemoteDebuggerBridge::ConnectionState RemoteDebuggerBridge::getConnectionState( void )
  171. {
  172. return BridgeState;
  173. }
  174. //-----------------------------------------------------------------------------
  175. StringTableEntry RemoteDebuggerBridge::getConnectionPassword( void )
  176. {
  177. return DebuggerPassword;
  178. }
  179. //-----------------------------------------------------------------------------
  180. void RemoteDebuggerBridge::WaitForClientConnection( void )
  181. {
  182. // Sanity!
  183. AssertFatal( BridgeState == Open, "Invalid bridge state waiting for connection." );
  184. // Info.
  185. Con::warnf( "Debugger version #%d waiting for client to connect on port %d...", DebuggerVersion, DebuggerPort );
  186. // Wait for connection.
  187. while( BridgeState == Open )
  188. {
  189. // Wait a while.
  190. Platform::sleep( IdleWaitPeriod );
  191. NetAddress address;
  192. NetSocket socket = Net::accept( ServerSocket, &address );
  193. // Skip if we don't have a valid socket.
  194. if ( socket == NetSocket::INVALID)
  195. continue;
  196. // Info.
  197. Con::printf( "Client connected to remote debugger (port '%d') at %d (port %d).",
  198. DebuggerPort,
  199. socket.getHash(),
  200. address.port );
  201. // Set client socket.
  202. ClientSocket = socket;
  203. // Set non-blocking socket.
  204. Net::setBlocking( ClientSocket, false );
  205. // Set bridge state.
  206. BridgeState = Connected;
  207. }
  208. }
  209. //-----------------------------------------------------------------------------
  210. void RemoteDebuggerBridge::WaitForClientLogin( void )
  211. {
  212. // Sanity!
  213. AssertFatal( BridgeState == Connected, "Invalid bridge state waiting for client log-in." );
  214. // Find remote debugger.
  215. RemoteDebuggerBase* pRemoteDebugger = Sim::findObject<RemoteDebuggerBase>( REMOTE_DEBUGGER_NAME );
  216. // Sanity!
  217. AssertFatal( pRemoteDebugger != NULL, "Could not find remote debugger waiting for client log-in." );
  218. // Info.
  219. Con::warnf( "Debugger version #%d waiting for client to authenticate on port %d...", DebuggerVersion, DebuggerPort );
  220. // Wait until the client has authenticated.
  221. while( !pRemoteDebugger->isClientAuthenticated() )
  222. {
  223. // Process the remote debugger explicitly.
  224. pRemoteDebugger->processTick();
  225. // Wait a while.
  226. Platform::sleep( IdleWaitPeriod );
  227. }
  228. }