Reputation: 14603
I'd like to embed my own shell into my C++ portable application, which would be accessible through TCP. The problem is I don't really know how to handle control characters, such as backspace, escape... Should I be looking into implementing, say, the telnet protocol? What simple way exists to tackle this problem?
NOTE:
I know that I am skirting the "opinion based" close reason, but maybe there exists a "canonical" way, that is widely used to solve this problem.
Upvotes: 0
Views: 531
Reputation: 73041
If your goal is to implement a fully functional telnet server (i.e. similar to the one provided by Linux, that can run arbitrary command line programs and can correctly handle anything a user might ever want to run, including pseudo-GUI programs like NetHack), then you'll have no choice but to implement most or all of RFC 854. The telnet protocol isn't trivial, but it's simpler than a lot of protocols, so doing that might not be quite as difficult as you think.
On the other hand, if you don't need "full telnet compatibility" and rather just want to provide a way for a user to log in to your program, send text commands to it, and read back the results, that's a lot easier -- just have your program accept TCP connections on a well-known port (it could even be the default telnet port, 23, although that would preclude running the standard telnet daemon on that port). Your program can simply send and receive ASCII strings over the accepted TCP connection(s), and that will more or less work with any telnet client, since the telnet protocol is designed to degrade gracefully and thus will still work in a basic mode even if the program at one end of the connection doesn't respond to any of telnet's special command-codes.
One minor problem with just blindly receiving bytes from a telnet client is that any command-codes coming from the telnet client might confuse your text parser. If that's an issue for you, you can do something like this to filter them out of the recv()'d data, just before you hand that data buffer over to your program's text-parsing routine:
// Rewrites a C character buffer in-place to remove any telnet command-codes from it
// @param buf Pointer to a buffer of data bytes just recv()'d from the telnet client
// @param bufLen The number of valid bytes that (buf) is pointing to
// @returns the number of valid data bytes that (buf) is pointing to after control codes were removed
int FilterInputBuffer(char * buf, int bufLen)
{
// persistent state variables, for the case where a telnet command gets split
// up across several incoming data buffers
static bool _inSubnegotiation = false;
static int _commandBytesLeft = 0;
// Based on the document at http://support.microsoft.com/kb/231866
static const unsigned char IAC = 255;
static const unsigned char SB = 250;
static const unsigned char SE = 240;
char * output = buf;
for (int i=0; i<bufLen; i++)
{
unsigned char c = buf[i];
bool keepChar = ((c & 0x80) == 0);
switch(c)
{
case IAC: _commandBytesLeft = 3; break;
case SB: _inSubnegotiation = true; break;
case SE: _inSubnegotiation = false; _commandBytesLeft = 0; break;
}
if (_commandBytesLeft > 0) {--_commandBytesLeft; keepChar = false;}
if (_inSubnegotiation) keepChar = false;
if (keepChar) *output++ = c; // strip out any telnet control/escape codes
}
return (output-buf); // return new (possibly shorter) data-buffer length
}
Upvotes: 2