ConsoleServer.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. #include "NativeFeatureIncludes.h"
  11. #if _RAKNET_SUPPORT_ConsoleServer==1
  12. #include "ConsoleServer.h"
  13. #include "TransportInterface.h"
  14. #include "CommandParserInterface.h"
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #define COMMAND_DELINATOR ' '
  18. #define COMMAND_DELINATOR_TOGGLE '"'
  19. #include "LinuxStrings.h"
  20. using namespace RakNet;
  21. STATIC_FACTORY_DEFINITIONS(ConsoleServer,ConsoleServer);
  22. ConsoleServer::ConsoleServer()
  23. {
  24. transport=0;
  25. password[0]=0;
  26. prompt=0;
  27. }
  28. ConsoleServer::~ConsoleServer()
  29. {
  30. if (prompt)
  31. rakFree_Ex(prompt, _FILE_AND_LINE_);
  32. }
  33. void ConsoleServer::SetTransportProvider(TransportInterface *transportInterface, unsigned short port)
  34. {
  35. // Replace the current TransportInterface, stopping the old one, if present, and starting the new one.
  36. if (transportInterface)
  37. {
  38. if (transport)
  39. {
  40. RemoveCommandParser(transport->GetCommandParser());
  41. transport->Stop();
  42. }
  43. transport=transportInterface;
  44. transport->Start(port, true);
  45. unsigned i;
  46. for (i=0; i < commandParserList.Size(); i++)
  47. commandParserList[i]->OnTransportChange(transport);
  48. // The transport itself might have a command parser - for example password for the RakNet transport
  49. AddCommandParser(transport->GetCommandParser());
  50. }
  51. }
  52. void ConsoleServer::AddCommandParser(CommandParserInterface *commandParserInterface)
  53. {
  54. if (commandParserInterface==0)
  55. return;
  56. // Non-duplicate insertion
  57. unsigned i;
  58. for (i=0; i < commandParserList.Size(); i++)
  59. {
  60. if (commandParserList[i]==commandParserInterface)
  61. return;
  62. if (_stricmp(commandParserList[i]->GetName(), commandParserInterface->GetName())==0)
  63. {
  64. // Naming conflict between two command parsers
  65. RakAssert(0);
  66. return;
  67. }
  68. }
  69. commandParserList.Insert(commandParserInterface, _FILE_AND_LINE_);
  70. if (transport)
  71. commandParserInterface->OnTransportChange(transport);
  72. }
  73. void ConsoleServer::RemoveCommandParser(CommandParserInterface *commandParserInterface)
  74. {
  75. if (commandParserInterface==0)
  76. return;
  77. // Overwrite the element we are removing from the back of the list and delete the back of the list
  78. unsigned i;
  79. for (i=0; i < commandParserList.Size(); i++)
  80. {
  81. if (commandParserList[i]==commandParserInterface)
  82. {
  83. commandParserList[i]=commandParserList[commandParserList.Size()-1];
  84. commandParserList.RemoveFromEnd();
  85. return;
  86. }
  87. }
  88. }
  89. void ConsoleServer::Update(void)
  90. {
  91. unsigned i;
  92. char *parameterList[20]; // Up to 20 parameters
  93. unsigned numParameters;
  94. RakNet::SystemAddress newOrLostConnectionId;
  95. RakNet::Packet *p;
  96. RakNet::RegisteredCommand rc;
  97. p = transport->Receive();
  98. newOrLostConnectionId=transport->HasNewIncomingConnection();
  99. if (newOrLostConnectionId!=UNASSIGNED_SYSTEM_ADDRESS)
  100. {
  101. for (i=0; i < commandParserList.Size(); i++)
  102. {
  103. commandParserList[i]->OnNewIncomingConnection(newOrLostConnectionId, transport);
  104. }
  105. transport->Send(newOrLostConnectionId, "Connected to remote command console.\r\nType 'help' for help.\r\n");
  106. ListParsers(newOrLostConnectionId);
  107. ShowPrompt(newOrLostConnectionId);
  108. }
  109. newOrLostConnectionId=transport->HasLostConnection();
  110. if (newOrLostConnectionId!=UNASSIGNED_SYSTEM_ADDRESS)
  111. {
  112. for (i=0; i < commandParserList.Size(); i++)
  113. commandParserList[i]->OnConnectionLost(newOrLostConnectionId, transport);
  114. }
  115. while (p)
  116. {
  117. bool commandParsed=false;
  118. char copy[REMOTE_MAX_TEXT_INPUT];
  119. memcpy(copy, p->data, p->length);
  120. copy[p->length]=0;
  121. RakNet::CommandParserInterface::ParseConsoleString((char*)p->data, COMMAND_DELINATOR, COMMAND_DELINATOR_TOGGLE, &numParameters, parameterList, 20); // Up to 20 parameters
  122. if (numParameters==0)
  123. {
  124. transport->DeallocatePacket(p);
  125. p = transport->Receive();
  126. continue;
  127. }
  128. if (_stricmp(*parameterList, "help")==0 && numParameters<=2)
  129. {
  130. // Find the parser specified and display help for it
  131. if (numParameters==1)
  132. {
  133. transport->Send(p->systemAddress, "\r\nINSTRUCTIONS:\r\n");
  134. transport->Send(p->systemAddress, "Enter commands on your keyboard, using spaces to delineate parameters.\r\n");
  135. transport->Send(p->systemAddress, "You can use quotation marks to toggle space delineation.\r\n");
  136. transport->Send(p->systemAddress, "You can connect multiple times from the same computer.\r\n");
  137. transport->Send(p->systemAddress, "You can direct commands to a parser by prefixing the parser name or number.\r\n");
  138. transport->Send(p->systemAddress, "COMMANDS:\r\n");
  139. transport->Send(p->systemAddress, "help Show this display.\r\n");
  140. transport->Send(p->systemAddress, "help <ParserName> Show help on a particular parser.\r\n");
  141. transport->Send(p->systemAddress, "help <CommandName> Show help on a particular command.\r\n");
  142. transport->Send(p->systemAddress, "quit Disconnects from the server.\r\n");
  143. transport->Send(p->systemAddress, "[<ParserName>] <Command> [<Parameters>] Execute a command\r\n");
  144. transport->Send(p->systemAddress, "[<ParserNumber>] <Command> [<Parameters>] Execute a command\r\n");
  145. ListParsers(p->systemAddress);
  146. //ShowPrompt(p->systemAddress);
  147. }
  148. else // numParameters == 2, including the help tag
  149. {
  150. for (i=0; i < commandParserList.Size(); i++)
  151. {
  152. if (_stricmp(parameterList[1], commandParserList[i]->GetName())==0)
  153. {
  154. commandParsed=true;
  155. commandParserList[i]->SendHelp(transport, p->systemAddress);
  156. transport->Send(p->systemAddress, "COMMAND LIST:\r\n");
  157. commandParserList[i]->SendCommandList(transport, p->systemAddress);
  158. transport->Send(p->systemAddress, "\r\n");
  159. break;
  160. }
  161. }
  162. if (commandParsed==false)
  163. {
  164. // Try again, for all commands for all parsers.
  165. RakNet::RegisteredCommand rc;
  166. for (i=0; i < commandParserList.Size(); i++)
  167. {
  168. if (commandParserList[i]->GetRegisteredCommand(parameterList[1], &rc))
  169. {
  170. if (rc.parameterCount==RakNet::CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS)
  171. transport->Send(p->systemAddress, "(Variable parms): %s %s\r\n", rc.command, rc.commandHelp);
  172. else
  173. transport->Send(p->systemAddress, "(%i parms): %s %s\r\n", rc.parameterCount, rc.command, rc.commandHelp);
  174. commandParsed=true;
  175. break;
  176. }
  177. }
  178. }
  179. if (commandParsed==false)
  180. {
  181. // Don't know what to do
  182. transport->Send(p->systemAddress, "Unknown help topic: %s.\r\n", parameterList[1]);
  183. }
  184. //ShowPrompt(p->systemAddress);
  185. }
  186. }
  187. else if (_stricmp(*parameterList, "quit")==0 && numParameters==1)
  188. {
  189. transport->Send(p->systemAddress, "Goodbye!\r\n");
  190. transport->CloseConnection(p->systemAddress);
  191. }
  192. else
  193. {
  194. bool tryAllParsers=true;
  195. bool failed=false;
  196. if (numParameters >=2) // At minimum <CommandParserName> <Command>
  197. {
  198. unsigned commandParserIndex=(unsigned)-1;
  199. // Prefixing with numbers directs to a particular parser
  200. if (**parameterList>='0' && **parameterList<='9')
  201. {
  202. commandParserIndex=atoi(*parameterList); // Use specified parser unless it's an invalid number
  203. commandParserIndex--; // Subtract 1 since we displayed numbers starting at index+1
  204. if (commandParserIndex >= commandParserList.Size())
  205. {
  206. transport->Send(p->systemAddress, "Invalid index.\r\n");
  207. failed=true;
  208. }
  209. }
  210. else
  211. {
  212. // // Prefixing with the name of a command parser directs to that parser. See if the first word matches a parser
  213. for (i=0; i < commandParserList.Size(); i++)
  214. {
  215. if (_stricmp(parameterList[0], commandParserList[i]->GetName())==0)
  216. {
  217. commandParserIndex=i; // Matches parser at index i
  218. break;
  219. }
  220. }
  221. }
  222. if (failed==false)
  223. {
  224. // -1 means undirected, so otherwise this is directed to a target
  225. if (commandParserIndex!=(unsigned)-1)
  226. {
  227. // Only this parser should use this command
  228. tryAllParsers=false;
  229. if (commandParserList[commandParserIndex]->GetRegisteredCommand(parameterList[1], &rc))
  230. {
  231. commandParsed=true;
  232. if (rc.parameterCount==CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS || rc.parameterCount==numParameters-2)
  233. commandParserList[commandParserIndex]->OnCommand(rc.command, numParameters-2, parameterList+2, transport, p->systemAddress, copy);
  234. else
  235. transport->Send(p->systemAddress, "Invalid parameter count.\r\n(%i parms): %s %s\r\n", rc.parameterCount, rc.command, rc.commandHelp);
  236. }
  237. }
  238. }
  239. }
  240. if (failed == false && tryAllParsers)
  241. {
  242. for (i=0; i < commandParserList.Size(); i++)
  243. {
  244. // Undirected command. Try all the parsers to see if they understand the command
  245. // Pass the 1nd element as the command, and the remainder as the parameter list
  246. if (commandParserList[i]->GetRegisteredCommand(parameterList[0], &rc))
  247. {
  248. commandParsed=true;
  249. if (rc.parameterCount==CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS || rc.parameterCount==numParameters-1)
  250. commandParserList[i]->OnCommand(rc.command, numParameters-1, parameterList+1, transport, p->systemAddress, copy);
  251. else
  252. transport->Send(p->systemAddress, "Invalid parameter count.\r\n(%i parms): %s %s\r\n", rc.parameterCount, rc.command, rc.commandHelp);
  253. }
  254. }
  255. }
  256. if (commandParsed==false && commandParserList.Size() > 0)
  257. {
  258. transport->Send(p->systemAddress, "Unknown command: Type 'help' for help.\r\n");
  259. }
  260. }
  261. ShowPrompt(p->systemAddress);
  262. transport->DeallocatePacket(p);
  263. p = transport->Receive();
  264. }
  265. }
  266. void ConsoleServer::ListParsers(SystemAddress systemAddress)
  267. {
  268. transport->Send(systemAddress,"INSTALLED PARSERS:\r\n");
  269. unsigned i;
  270. for (i=0; i < commandParserList.Size(); i++)
  271. {
  272. transport->Send(systemAddress, "%i. %s\r\n", i+1, commandParserList[i]->GetName());
  273. }
  274. }
  275. void ConsoleServer::ShowPrompt(SystemAddress systemAddress)
  276. {
  277. transport->Send(systemAddress, prompt);
  278. }
  279. void ConsoleServer::SetPrompt(const char *_prompt)
  280. {
  281. if (prompt)
  282. rakFree_Ex(prompt,_FILE_AND_LINE_);
  283. if (_prompt && _prompt[0])
  284. {
  285. size_t len = strlen(_prompt);
  286. prompt = (char*) rakMalloc_Ex(len+1,_FILE_AND_LINE_);
  287. strcpy(prompt,_prompt);
  288. }
  289. else
  290. prompt=0;
  291. }
  292. #endif // _RAKNET_SUPPORT_*
粤ICP备19079148号