Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

343 lines
9.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: defines a RCon class used to send rcon commands to remote servers
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================
  7. #include "rcon.h"
  8. #include "Iresponse.h"
  9. #include "RconMsgHandler.h"
  10. #include "Socket.h"
  11. #include "proto_oob.h"
  12. #include "DialogGameInfo.h"
  13. #include "inetapi.h"
  14. #include "dialogkickplayer.h"
  15. extern void v_strncpy(char *dest, const char *src, int bufsize);
  16. typedef enum
  17. {
  18. NONE = 0,
  19. INFO_REQUESTED,
  20. INFO_RECEIVED
  21. } RCONSTATUS;
  22. CRcon::CRcon(IResponse *target,serveritem_t &server,const char *password) {
  23. memcpy(&m_Server, &server,sizeof(serveritem_t));
  24. m_pResponseTarget=target;
  25. m_bIsRefreshing = false;
  26. m_bChallenge = false;
  27. m_bNewRcon = false;
  28. m_bPasswordFail = false;
  29. m_bDisable = false;
  30. m_bGotChallenge = false;
  31. m_iChallenge = 0;
  32. m_fQuerySendTime= 0;
  33. v_strncpy(m_sPassword,password,100);
  34. int bytecode = S2A_INFO_DETAILED;
  35. m_pQuery = new CSocket("internet rcon query", -1);
  36. m_pQuery->AddMessageHandler(new CRconMsgHandlerDetails(this, CMsgHandler::MSGHANDLER_ALL, &bytecode));
  37. }
  38. CRcon::~CRcon() {
  39. delete m_pQuery;
  40. }
  41. //-----------------------------------------------------------------------------
  42. // Purpose: resets the state of the rcon object back to startup conditions (i.e get challenge again)
  43. //-----------------------------------------------------------------------------
  44. void CRcon::Reset()
  45. {
  46. m_bIsRefreshing = false;
  47. m_bChallenge = false;
  48. m_bNewRcon = false;
  49. m_bPasswordFail = false;
  50. m_bDisable = false;
  51. m_bGotChallenge = false;
  52. m_iChallenge = 0;
  53. m_fQuerySendTime= 0;
  54. }
  55. //-----------------------------------------------------------------------------
  56. // Purpose: sends a challenge request to the server if we have yet to get one,
  57. // else it sends the rcon itself
  58. //-----------------------------------------------------------------------------
  59. void CRcon::SendRcon(const char *command)
  60. {
  61. if(m_bDisable==true) // rcon is disabled because it has failed.
  62. {
  63. m_pResponseTarget->ServerFailedToRespond();
  64. return;
  65. }
  66. if(m_bIsRefreshing)
  67. { // we are already processing a request, lets queue this
  68. queue_requests_t queue;
  69. strncpy(queue.queued,command,1024);
  70. if(requests.Count()>10) // to many request already...
  71. return;
  72. requests.AddToTail(queue);
  73. return;
  74. }
  75. m_bIsRefreshing=true;
  76. m_bPasswordFail=false;
  77. if(m_bGotChallenge==false) // haven't got the challenge id yet
  78. {
  79. GetChallenge();
  80. v_strncpy(m_sCmd,command,1024); // store away the command for later :)
  81. m_bChallenge=true; // note that we are requesting a challenge and need to still run this command
  82. }
  83. else
  84. {
  85. RconRequest(command,m_iChallenge);
  86. }
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Purpose: runs a frame of the net handler
  90. //-----------------------------------------------------------------------------
  91. void CRcon::RunFrame()
  92. {
  93. // only the "ping" command has a timeout
  94. /* float curtime = CSocket::GetClock();
  95. if(m_fQuerySendTime!=0 && (curtime-m_fQuerySendTime)> 10.0f) // 10 seconds
  96. {
  97. m_fQuerySendTime= 0;
  98. m_pResponseTarget->ServerFailedToRespond();
  99. }
  100. */
  101. if (m_pQuery)
  102. {
  103. m_pQuery->Frame();
  104. }
  105. }
  106. //-----------------------------------------------------------------------------
  107. // Purpose: emits a challenge request
  108. //-----------------------------------------------------------------------------
  109. void CRcon::GetChallenge()
  110. {
  111. CMsgBuffer *buffer = m_pQuery->GetSendBuffer();
  112. assert( buffer );
  113. if ( !buffer )
  114. {
  115. return;
  116. }
  117. netadr_t adr;
  118. adr.ip[0] = m_Server.ip[0];
  119. adr.ip[1] = m_Server.ip[1];
  120. adr.ip[2] = m_Server.ip[2];
  121. adr.ip[3] = m_Server.ip[3];
  122. adr.port = (m_Server.port & 0xff) << 8 | (m_Server.port & 0xff00) >> 8;
  123. adr.type = NA_IP;
  124. // Set state
  125. m_Server.received = (int)INFO_REQUESTED;
  126. // Create query message
  127. buffer->Clear();
  128. // Write control sequence
  129. buffer->WriteLong(0xffffffff);
  130. // Write query string
  131. buffer->WriteString("challenge rcon");
  132. // Sendmessage
  133. m_pQuery->SendMessage( &adr );
  134. // set the clock for this send
  135. m_fQuerySendTime = CSocket::GetClock();
  136. }
  137. //-----------------------------------------------------------------------------
  138. // Purpose: emits a valid rcon request, the challenge id has already been found
  139. //-----------------------------------------------------------------------------
  140. void CRcon::RconRequest(const char *command, int challenge)
  141. {
  142. CMsgBuffer *buffer = m_pQuery->GetSendBuffer();
  143. assert( buffer );
  144. if ( !buffer )
  145. {
  146. return;
  147. }
  148. netadr_t adr;
  149. adr.ip[0] = m_Server.ip[0];
  150. adr.ip[1] = m_Server.ip[1];
  151. adr.ip[2] = m_Server.ip[2];
  152. adr.ip[3] = m_Server.ip[3];
  153. adr.port = (m_Server.port & 0xff) << 8 | (m_Server.port & 0xff00) >> 8;
  154. adr.type = NA_IP;
  155. // Set state
  156. m_Server.received = (int)INFO_REQUESTED;
  157. // Create query message
  158. buffer->Clear();
  159. // Write control sequence
  160. buffer->WriteLong(0xffffffff);
  161. // Write query string
  162. char rcon_cmd[600];
  163. _snprintf(rcon_cmd,600,"rcon %u \"%s\" %s",challenge,m_sPassword,command);
  164. buffer->WriteString(rcon_cmd);
  165. // Sendmessage
  166. m_pQuery->SendMessage( &adr );
  167. // set the clock for this send
  168. m_fQuerySendTime = CSocket::GetClock();
  169. }
  170. //-----------------------------------------------------------------------------
  171. // Purpose: called when an rcon responds
  172. //-----------------------------------------------------------------------------
  173. void CRcon::UpdateServer(netadr_t *adr, int challenge, const char *resp)
  174. {
  175. m_fQuerySendTime= 0;
  176. if(m_bChallenge==true) // now send the RCON request itself
  177. {
  178. m_bChallenge=false; // m_bChallenge is set to say we just requested the challenge value
  179. m_iChallenge=challenge;
  180. m_bGotChallenge=true;
  181. RconRequest(m_sCmd,m_iChallenge);
  182. }
  183. else // this is the result of the RCON request
  184. {
  185. m_bNewRcon=true;
  186. v_strncpy(m_sRconResponse,resp,2048);
  187. m_bIsRefreshing=false;
  188. // this must be before the SeverResponded() :)
  189. if(requests.Count()>0)
  190. { // we have queued requests
  191. SendRcon(requests[0].queued);
  192. requests.Remove(0); // now delete this element
  193. }
  194. // notify the UI of the new server info
  195. m_pResponseTarget->ServerResponded();
  196. }
  197. }
  198. //-----------------------------------------------------------------------------
  199. // Purpose: run when a refresh is asked for
  200. //-----------------------------------------------------------------------------
  201. void CRcon::Refresh()
  202. {
  203. }
  204. //-----------------------------------------------------------------------------
  205. // Purpose: returns if a rcon is currently being performed
  206. //-----------------------------------------------------------------------------
  207. bool CRcon::IsRefreshing()
  208. {
  209. return m_bIsRefreshing;
  210. }
  211. //-----------------------------------------------------------------------------
  212. // Purpose: the server to which this rcon class is bound
  213. //-----------------------------------------------------------------------------
  214. serveritem_t &CRcon::GetServer()
  215. {
  216. return m_Server;
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Purpose: the challenge id used in rcons
  220. //-----------------------------------------------------------------------------
  221. bool CRcon::Challenge()
  222. {
  223. return m_bChallenge;
  224. }
  225. //-----------------------------------------------------------------------------
  226. // Purpose: returns if a new rcon result is available
  227. //-----------------------------------------------------------------------------
  228. bool CRcon::NewRcon()
  229. {
  230. bool val = m_bNewRcon;
  231. m_bNewRcon=false;
  232. return val;
  233. }
  234. //-----------------------------------------------------------------------------
  235. // Purpose: returns the response of the last rcon
  236. //-----------------------------------------------------------------------------
  237. const char *CRcon::RconResponse()
  238. {
  239. return (const char *)m_sRconResponse;
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Purpose: called when the wrong password is used, when a ServerFailed is called
  243. //-----------------------------------------------------------------------------
  244. bool CRcon::PasswordFail()
  245. {
  246. bool val=m_bPasswordFail;
  247. m_bPasswordFail=false;
  248. return val;
  249. //m_pResponseTarget->ServerFailedToRespond();
  250. }
  251. //-----------------------------------------------------------------------------
  252. // Purpose: called by the rcon message handler to denote a bad password
  253. //-----------------------------------------------------------------------------
  254. void CRcon::BadPassword(const char *info)
  255. {
  256. strncpy(m_sRconResponse,info,100);
  257. m_bPasswordFail=true;
  258. m_bDisable=true;
  259. m_fQuerySendTime= 0;
  260. m_bIsRefreshing=false;
  261. /* // this must be before the ServerFailedToRespond() :)
  262. if(requests.Count()>0)
  263. { // we have queued requests
  264. SendRcon(requests[0].queued);
  265. requests.Remove(0); // now delete this element
  266. }
  267. */
  268. m_pResponseTarget->ServerFailedToRespond();
  269. }
  270. //-----------------------------------------------------------------------------
  271. // Purpose: return whether rcon has been disabled (due to bad passwords)
  272. //-----------------------------------------------------------------------------
  273. bool CRcon::Disabled()
  274. {
  275. return m_bDisable;
  276. }
  277. //-----------------------------------------------------------------------------
  278. // Purpose: sets the password to use for rcons
  279. //-----------------------------------------------------------------------------
  280. void CRcon::SetPassword(const char *newPass)
  281. {
  282. strncpy(m_sPassword,newPass,100);
  283. m_bDisable=false; // new password, so we can try again
  284. }