Torque3D Documentation / _generateds / telnetConsole.cpp

telnetConsole.cpp

Engine/source/console/telnetConsole.cpp

More...

Public Functions

DefineEngineFunction(telnetSetParameters , void , (int port, const char *consolePass, const char *listenPass, bool remoteEcho) , (false) , "@brief Initializes and open the telnet <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n\n</a>" "@param port Port <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> listen on <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> console connections (0 will shut down listening).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param consolePass Password <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> read/write access <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n</a>" "@param listenPass Password <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> read access <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n</a>" "@param remoteEcho  Enable echoing back <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the client, off by <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">default.\n\n</a>" " @ingroup Debugging" )
telnetCallback(U32 level, const char * consoleLine)

Detailed Description

Public Variables

 MODULE_END 
 MODULE_INIT 
 MODULE_SHUTDOWN 
TelnetConsole * TelConsole 

Public Functions

DefineEngineFunction(telnetSetParameters , void , (int port, const char *consolePass, const char *listenPass, bool remoteEcho) , (false) , "@brief Initializes and open the telnet <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n\n</a>" "@param port Port <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> listen on <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> console connections (0 will shut down listening).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param consolePass Password <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> read/write access <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n</a>" "@param listenPass Password <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> read access <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">console.\n</a>" "@param remoteEcho  Enable echoing back <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the client, off by <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">default.\n\n</a>" " @ingroup Debugging" )

telnetCallback(U32 level, const char * consoleLine)

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25
 26#include "console/simBase.h"
 27#include "console/engineAPI.h"
 28#include "console/telnetConsole.h"
 29
 30#include "core/strings/stringFunctions.h"
 31#include "core/util/journal/process.h"
 32#include "core/module.h"
 33
 34
 35MODULE_BEGIN( TelnetConsole )
 36
 37   MODULE_INIT
 38   {
 39      TelnetConsole::create();
 40   }
 41   
 42   MODULE_SHUTDOWN
 43   {
 44      TelnetConsole::destroy();
 45   }
 46
 47MODULE_END;
 48
 49
 50TelnetConsole *TelConsole = NULL;
 51
 52void TelnetConsole::create()
 53{
 54   TelConsole = new TelnetConsole;
 55   Process::notify(TelConsole, &TelnetConsole::process, PROCESS_FIRST_ORDER);
 56}
 57
 58void TelnetConsole::destroy()
 59{
 60   Process::remove(TelConsole, &TelnetConsole::process);
 61   delete TelConsole;
 62   TelConsole = NULL;
 63}
 64
 65DefineEngineFunction( telnetSetParameters, void, ( int port, const char* consolePass, const char* listenPass, bool remoteEcho ), ( false ),
 66                "@brief Initializes and open the telnet console.\n\n"
 67                "@param port        Port to listen on for console connections (0 will shut down listening).\n"
 68                "@param consolePass Password for read/write access to console.\n"
 69                "@param listenPass  Password for read access to console.\n"
 70                "@param remoteEcho  [optional] Enable echoing back to the client, off by default.\n\n"
 71            "@ingroup Debugging")
 72{
 73   if (TelConsole)
 74      TelConsole->setTelnetParameters(port, consolePass, listenPass, remoteEcho);
 75}
 76
 77static void telnetCallback(U32 level, const char *consoleLine)
 78{
 79   TORQUE_UNUSED(level);
 80   if (TelConsole)
 81     TelConsole->processConsoleLine(consoleLine);
 82}
 83
 84TelnetConsole::TelnetConsole()
 85{
 86   Con::addConsumer(telnetCallback);
 87
 88   mAcceptSocket = NetSocket::INVALID;
 89   mAcceptPort = -1;
 90   mClientList = NULL;
 91   mRemoteEchoEnabled = false;
 92
 93   dStrncpy(mTelnetPassword, "", PasswordMaxLength);
 94   dStrncpy(mListenPassword, "", PasswordMaxLength);
 95}
 96
 97TelnetConsole::~TelnetConsole()
 98{
 99   Con::removeConsumer(telnetCallback);
100   if(mAcceptSocket != NetSocket::INVALID)
101      Net::closeSocket(mAcceptSocket);
102   TelnetClient *walk = mClientList, *temp;
103   while(walk)
104   {
105      temp = walk->nextClient;
106      if(walk->socket != NetSocket::INVALID)
107         Net::closeSocket(walk->socket);
108      delete walk;
109      walk = temp;
110   }
111}
112
113void TelnetConsole::setTelnetParameters(S32 port, const char *telnetPassword, const char *listenPassword, bool remoteEcho)
114{
115   if(port == mAcceptPort)
116      return;
117
118   mRemoteEchoEnabled = remoteEcho;
119
120   if(mAcceptSocket != NetSocket::INVALID)
121   {
122      Net::closeSocket(mAcceptSocket);
123      mAcceptSocket = NetSocket::INVALID;
124   }
125   mAcceptPort = port;
126   if(mAcceptPort != -1 && mAcceptPort != 0)
127   {
128     NetAddress address;
129     Net::getIdealListenAddress(&address);
130     address.port = mAcceptPort;
131
132      mAcceptSocket = Net::openSocket();
133      Net::bindAddress(address, mAcceptSocket);
134      Net::listen(mAcceptSocket, 4);
135
136      Net::setBlocking(mAcceptSocket, false);
137   }
138   dStrncpy(mTelnetPassword, telnetPassword, PasswordMaxLength);
139   dStrncpy(mListenPassword, listenPassword, PasswordMaxLength);
140}
141
142void TelnetConsole::processConsoleLine(const char *consoleLine)
143{
144   if (mClientList==<a href="/coding/file/types_8lint_8h/#types_8lint_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a>) return;  // just escape early.  don't even do another step...
145
146   // ok, spew this line out to all our subscribers...
147   S32 len = dStrlen(consoleLine)+1;
148   for(TelnetClient *walk = mClientList; walk; walk = walk->nextClient)
149   {
150      if(walk->state == FullAccessConnected || walk->state == ReadOnlyConnected)
151      {
152         Net::send(walk->socket, (const unsigned char*)consoleLine, len);
153         Net::send(walk->socket, (const unsigned char*)"\r\n", 2);
154      }
155   }
156}
157
158void TelnetConsole::process()
159{
160   NetAddress address;
161
162   if(mAcceptSocket != NetSocket::INVALID)
163   {
164      // ok, see if we have any new connections:
165      NetSocket newConnection;
166      newConnection = Net::accept(mAcceptSocket, &address);
167
168      if(newConnection != NetSocket::INVALID)
169      {
170         char buffer[256];
171         Net::addressToString(&address, buffer);
172         Con::printf("Telnet connection from %s", buffer);
173
174         TelnetClient *cl = new TelnetClient;
175         cl->socket = newConnection;
176         cl->curPos = 0;
177#if defined(TORQUE_SHIPPING) && defined(TORQUE_DISABLE_TELNET_CONSOLE_PASSWORD)
178         // disable the password in a ship build? WTF.  lets make an error:
179         PleaseMakeSureYouKnowWhatYouAreDoingAndCommentOutThisLineIfSo.
180#elif !defined(TORQUE_SHIPPING) && defined(TORQUE_DISABLE_TELNET_CONSOLE_PASSWORD)
181         cl->state = FullAccessConnected;
182#else
183         cl->state = PasswordTryOne;
184#endif
185
186         Net::setBlocking(newConnection, false);
187
188         const char *prompt = Con::getVariable("Con::Prompt");
189         char connectMessage[1024];
190         dSprintf(connectMessage, sizeof(connectMessage), 
191            "Torque Telnet Remote Console\r\n\r\n%s",
192            cl->state == FullAccessConnected ? prompt : "Enter Password:");
193
194         Net::send(cl->socket, (const unsigned char*)connectMessage, dStrlen(connectMessage)+1);
195         cl->nextClient = mClientList;
196         mClientList = cl;
197      }
198   }
199
200   char recvBuf[256];
201   char reply[1024];
202
203   // see if we have any input to process...
204
205   for(TelnetClient *client = mClientList; client; client = client->nextClient)
206   {
207      S32 numBytes;
208      Net::Error err = Net::recv(client->socket, (unsigned char*)recvBuf, sizeof(recvBuf), &numBytes);
209
210      if((err != Net::NoError && err != Net::WouldBlock) || numBytes == 0)
211      {
212         Net::closeSocket(client->socket);
213         client->socket = NetSocket::INVALID;
214         continue;
215      }
216
217      S32 replyPos = 0;
218      for(S32 i = 0; i < numBytes;i++)
219      {
220         if(recvBuf[i] == '\r')
221            continue;
222         // execute the current command
223
224         if(recvBuf[i] == '\n')
225         {
226            reply[replyPos++] = '\r';
227            reply[replyPos++] = '\n';
228
229            client->curLine[client->curPos] = 0;
230            client->curPos = 0;
231
232            if(client->state == FullAccessConnected)
233            {
234               Net::send(client->socket, (const unsigned char*)reply, replyPos);
235               replyPos = 0;
236
237               // Notify console of line to execute.
238               RawData rd;
239               rd.size = dStrlen(client->curLine) + 1;
240               rd.data = ( S8* ) client->curLine;
241               Con::smConsoleInput.trigger(rd);
242
243               // note - send prompt next
244               const char *prompt = Con::getVariable("Con::Prompt");
245               Net::send(client->socket, (const unsigned char*)prompt, dStrlen(prompt));
246            }
247            else if(client->state == ReadOnlyConnected)
248            {
249               Net::send(client->socket, (const unsigned char*)reply, replyPos);
250               replyPos = 0;
251            }
252            else
253            {
254               client->state++;
255               if(!dStrncmp(client->curLine, mTelnetPassword, PasswordMaxLength))
256               {
257                  Net::send(client->socket, (const unsigned char*)reply, replyPos);
258                  replyPos = 0;
259
260                  // send prompt
261                  const char *prompt = Con::getVariable("Con::Prompt");
262                  Net::send(client->socket, (const unsigned char*)prompt, dStrlen(prompt));
263                  client->state = FullAccessConnected;
264               }
265               else if(!dStrncmp(client->curLine, mListenPassword, PasswordMaxLength))
266               {
267                  Net::send(client->socket, (const unsigned char*)reply, replyPos);
268                  replyPos = 0;
269
270                  // send prompt
271                  const char *listenConnected = "Connected.\r\n";
272                  Net::send(client->socket, (const unsigned char*)listenConnected, dStrlen(listenConnected));
273                  client->state = ReadOnlyConnected;
274               }
275               else
276               {
277                  const char *sendStr;
278                  if(client->state == DisconnectThisDude)
279                     sendStr = "Too many tries... cya.";
280                  else
281                     sendStr = "Nope... try agian.\r\nEnter Password:";
282                  Net::send(client->socket, (const unsigned char*)sendStr, dStrlen(sendStr));
283                  if(client->state == DisconnectThisDude)
284                  {
285                     Net::closeSocket(client->socket);
286                     client->socket = NetSocket::INVALID;
287                  }
288               }
289            }
290         }
291         else if(recvBuf[i] == '\b')
292         {
293            // pull the old backspace manuever...
294            if(client->curPos > 0)
295            {
296               client->curPos--;
297               if(client->state == FullAccessConnected)
298               {
299                  reply[replyPos++] = '\b';
300                  reply[replyPos++] = ' ';
301                  reply[replyPos++] = '\b';
302               }
303            }
304         }
305         else if(client->curPos < Con::MaxLineLength-1)
306         {
307            client->curLine[client->curPos++] = recvBuf[i];
308            // don't echo password chars...
309            if(client->state == FullAccessConnected)
310               reply[replyPos++] = recvBuf[i];
311         }
312      }
313
314      // Echo the character back to the user, unless the remote echo
315      // is disabled (by default)
316      if(replyPos && mRemoteEchoEnabled)
317         Net::send(client->socket, (const unsigned char*)reply, replyPos);
318   }
319
320   TelnetClient ** walk = &mClientList;
321   TelnetClient *cl;
322   while((cl = *walk) != NULL)
323   {
324      if(cl->socket == NetSocket::INVALID)
325      {
326         *walk = cl->nextClient;
327         delete cl;
328      }
329      else
330         walk = &cl->nextClient;
331   }
332}
333