From: curt Date: Wed, 15 May 2002 21:44:34 +0000 (+0000) Subject: Bernie Bright: X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=f9f05aa8704a198604b0285413562f434402f9cb;p=flightgear.git Bernie Bright: Here is the new super improved telnet property interface. CVS changelog is at the end of this message. Once this new telnet code is in and compiles every where we can remove Network/props.[ch]xx. I've added a --telnet= command line option to invoke the new server. Later on we could remove the --props option, or least change it to invoke the new server. I'll let you decide. I've added some new commands to the telnet interface: view next Select the next view. view prev Select the previous view. view set Select view 'n' view get Return index of current view I'm not sure if these same effects could be achieved through property operations. The commands provide a convenient shortcut in any case. I'm also planning on adding a panel command to manipulate panels and objects contained therein (eg simulated mouse clicks). There is going to be some commonality with the command objects so we may need to rationalize this in the near future. Finally, I've also included my python stuff. This is still very much a work in progress, basically I've been using it to test the new telnet server. I have tested it with python 2.2. Feel free to add it to the repository if you want. I would suggest a scripts/python directory CVS Changelog Network/telnet.cxx: New property telnet protocol interface. It supports the same user interface provided by the --props server. Additionally it handles multiple simultaneous connections. Added "view" command to manipulate viewmgr. Network/protocol.hxx: Added protocol configuration exception. Main/fg_io.cxx: Added new "telnet" protocol. Added protocol configuration parse exceptions. Simplified protocol configuration parsing. Main/options.cxx: Added --telnet= command line option and help message. --- diff --git a/src/Main/fg_io.cxx b/src/Main/fg_io.cxx index d98cc0769..e6352f0c5 100644 --- a/src/Main/fg_io.cxx +++ b/src/Main/fg_io.cxx @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -51,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -68,172 +70,126 @@ io_container global_io_list; // configure a port based on the config string static FGProtocol *parse_port_config( const string& config ) { - bool short_circuit = false; - - string::size_type begin, end; - - begin = 0; - SG_LOG( SG_IO, SG_INFO, "Parse I/O channel request: " << config ); - // determine protocol - end = config.find(",", begin); - if ( end == string::npos ) { - return NULL; // dummy + vector tokens = simgear::strutils::split( config, "," ); + if (tokens.empty()) + { + SG_LOG( SG_IO, SG_ALERT, + "Port configuration error: empty config string" ); + return 0; } - - string protocol = config.substr(begin, end - begin); - begin = end + 1; + + string protocol = tokens[0]; SG_LOG( SG_IO, SG_INFO, " protocol = " << protocol ); - FGProtocol *io; - if ( protocol == "atc610x" ) { - FGATC610x *atc610x = new FGATC610x; - io = atc610x; - short_circuit = true; - cout << "here ..." << endl; - } else if ( protocol == "atlas" ) { - FGAtlas *atlas = new FGAtlas; - io = atlas; - } else if ( protocol == "opengc" ) { - // char wait; - // printf("Parsed opengc\n"); cin >> wait; - FGOpenGC *opengc = new FGOpenGC; - io = opengc; - } else if ( protocol == "garmin" ) { - FGGarmin *garmin = new FGGarmin; - io = garmin; - } else if ( protocol == "httpd" ) { - // determine port - string port = config.substr(begin); - FGHttpd *httpd = new FGHttpd( atoi(port.c_str()) ); - io = httpd; - short_circuit = true; + FGProtocol *io = 0; + + try + { + if ( protocol == "atc610x" ) { + return new FGATC610x; + } else if ( protocol == "atlas" ) { + FGAtlas *atlas = new FGAtlas; + io = atlas; + } else if ( protocol == "opengc" ) { + // char wait; + // printf("Parsed opengc\n"); cin >> wait; + FGOpenGC *opengc = new FGOpenGC; + io = opengc; + } else if ( protocol == "garmin" ) { + FGGarmin *garmin = new FGGarmin; + io = garmin; + } else if ( protocol == "httpd" ) { + // determine port + string port = tokens[1]; + return new FGHttpd( atoi(port.c_str()) ); #ifdef FG_JPEG_SERVER - } else if ( protocol == "jpg-httpd" ) { - // determine port - string port = config.substr(begin); - FGJpegHttpd *jpeg_httpd = new FGJpegHttpd( atoi(port.c_str()) ); - io = jpeg_httpd; - short_circuit = true; + } else if ( protocol == "jpg-httpd" ) { + // determine port + string port = tokens[1]; + return new FGJpegHttpd( atoi(port.c_str()) ); #endif - } else if ( protocol == "joyclient" ) { - FGJoyClient *joyclient = new FGJoyClient; - io = joyclient; - } else if ( protocol == "native" ) { - FGNative *native = new FGNative; - io = native; - } else if ( protocol == "native_ctrls" ) { - FGNativeCtrls *native_ctrls = new FGNativeCtrls; - io = native_ctrls; - } else if ( protocol == "native_fdm" ) { - FGNativeFDM *native_fdm = new FGNativeFDM; - io = native_fdm; - } else if ( protocol == "nmea" ) { - FGNMEA *nmea = new FGNMEA; - io = nmea; - } else if ( protocol == "props" ) { - FGProps *props = new FGProps; - io = props; - } else if ( protocol == "pve" ) { - FGPVE *pve = new FGPVE; - io = pve; - } else if ( protocol == "ray" ) { - FGRAY *ray = new FGRAY; - io = ray; - } else if ( protocol == "rul" ) { - FGRUL *rul = new FGRUL; - io = rul; - } else { - return NULL; + } else if ( protocol == "joyclient" ) { + FGJoyClient *joyclient = new FGJoyClient; + io = joyclient; + } else if ( protocol == "native" ) { + FGNative *native = new FGNative; + io = native; + } else if ( protocol == "native_ctrls" ) { + FGNativeCtrls *native_ctrls = new FGNativeCtrls; + io = native_ctrls; + } else if ( protocol == "native_fdm" ) { + FGNativeFDM *native_fdm = new FGNativeFDM; + io = native_fdm; + } else if ( protocol == "nmea" ) { + FGNMEA *nmea = new FGNMEA; + io = nmea; + } else if ( protocol == "props" ) { + io = new FGProps(); + } else if ( protocol == "telnet" ) { + io = new FGTelnet( tokens ); + return io; + } else if ( protocol == "pve" ) { + FGPVE *pve = new FGPVE; + io = pve; + } else if ( protocol == "ray" ) { + FGRAY *ray = new FGRAY; + io = ray; + } else if ( protocol == "rul" ) { + FGRUL *rul = new FGRUL; + io = rul; + } else { + return NULL; + } + } + catch (FGProtocolConfigError& err) + { + SG_LOG( SG_IO, SG_ALERT, "Port configuration error: " << err.what() ); + delete io; + return 0; } - if ( ! short_circuit ) { - // determine medium - end = config.find(",", begin); - if ( end == string::npos ) { - return NULL; // dummy - } - - string medium = config.substr(begin, end - begin); - begin = end + 1; - SG_LOG( SG_IO, SG_INFO, " medium = " << medium ); - - // determine direction - end = config.find(",", begin); - if ( end == string::npos ) { - return NULL; // dummy - } - - string direction = config.substr(begin, end - begin); - begin = end + 1; - io->set_direction( direction ); - SG_LOG( SG_IO, SG_INFO, " direction = " << direction ); - - // determine hertz - end = config.find(",", begin); - if ( end == string::npos ) { - return NULL; // dummy - } - - string hertz_str = config.substr(begin, end - begin); - begin = end + 1; - double hertz = atof( hertz_str.c_str() ); - io->set_hz( hertz ); - SG_LOG( SG_IO, SG_INFO, " hertz = " << hertz ); - - if ( medium == "serial" ) { - // device name - end = config.find(",", begin); - if ( end == string::npos ) { - return NULL; - } - - string device = config.substr(begin, end - begin); - begin = end + 1; - SG_LOG( SG_IO, SG_INFO, " device = " << device ); - - // baud - string baud = config.substr(begin); - SG_LOG( SG_IO, SG_INFO, " baud = " << baud ); - - SGSerial *ch = new SGSerial( device, baud ); - io->set_io_channel( ch ); - } else if ( medium == "file" ) { - // file name - string file = config.substr(begin); - SG_LOG( SG_IO, SG_INFO, " file name = " << file ); - - SGFile *ch = new SGFile( file ); - io->set_io_channel( ch ); - } else if ( medium == "socket" ) { - // hostname - end = config.find(",", begin); - if ( end == string::npos ) { - return NULL; - } - - string hostname = config.substr(begin, end - begin); - begin = end + 1; - SG_LOG( SG_IO, SG_INFO, " hostname = " << hostname ); - - // port string - end = config.find(",", begin); - if ( end == string::npos ) { - return NULL; - } - - string port = config.substr(begin, end - begin); - begin = end + 1; - SG_LOG( SG_IO, SG_INFO, " port string = " << port ); - - // socket style - string style_str = config.substr(begin); - SG_LOG( SG_IO, SG_INFO, " style string = " << style_str ); + string medium = tokens[1]; + SG_LOG( SG_IO, SG_INFO, " medium = " << medium ); + + string direction = tokens[2]; + io->set_direction( direction ); + SG_LOG( SG_IO, SG_INFO, " direction = " << direction ); + + string hertz_str = tokens[3]; + double hertz = atof( hertz_str.c_str() ); + io->set_hz( hertz ); + SG_LOG( SG_IO, SG_INFO, " hertz = " << hertz ); + + if ( medium == "serial" ) { + // device name + string device = tokens[4]; + SG_LOG( SG_IO, SG_INFO, " device = " << device ); + + // baud + string baud = tokens[5]; + SG_LOG( SG_IO, SG_INFO, " baud = " << baud ); + + SGSerial *ch = new SGSerial( device, baud ); + io->set_io_channel( ch ); + } else if ( medium == "file" ) { + // file name + string file = tokens[4]; + SG_LOG( SG_IO, SG_INFO, " file name = " << file ); + + SGFile *ch = new SGFile( file ); + io->set_io_channel( ch ); + } else if ( medium == "socket" ) { + string hostname = tokens[4]; + string port = tokens[5]; + string style = tokens[6]; + + SG_LOG( SG_IO, SG_INFO, " hostname = " << hostname ); + SG_LOG( SG_IO, SG_INFO, " port = " << port ); + SG_LOG( SG_IO, SG_INFO, " style = " << style ); - SGSocket *ch = new SGSocket( hostname, port, style_str ); - io->set_io_channel( ch ); - } + io->set_io_channel( new SGSocket( hostname, port, style ) ); } return io; @@ -273,8 +229,6 @@ void fgIOInit() { // process any serial port work void fgIOProcess() { - FGProtocol *p; - // cout << "processing I/O channels" << endl; static int inited = 0; @@ -292,9 +246,9 @@ void fgIOProcess() { last = current; } - for ( int i = 0; i < (int)global_io_list.size(); ++i ) { + for ( unsigned int i = 0; i < global_io_list.size(); ++i ) { // cout << " channel = " << i << endl; - p = global_io_list[i]; + FGProtocol* p = global_io_list[i]; if ( p->is_enabled() ) { p->dec_count_down( interval ); diff --git a/src/Main/main.cxx b/src/Main/main.cxx index dc0ec237f..11e2ef141 100644 --- a/src/Main/main.cxx +++ b/src/Main/main.cxx @@ -1332,7 +1332,8 @@ int mainLoop( int argc, char **argv ) { version = "unknown version"; #endif SG_LOG( SG_GENERAL, SG_INFO, "FlightGear: Version " - << version << endl ); + << version ); + SG_LOG( SG_GENERAL, SG_INFO, "Built with " << SG_COMPILER_STR ); // Allocate global data structures. This needs to happen before // we parse command line options diff --git a/src/Network/Makefile.am b/src/Network/Makefile.am index 7766c0977..de3c00fde 100644 --- a/src/Network/Makefile.am +++ b/src/Network/Makefile.am @@ -24,7 +24,8 @@ libNetwork_a_SOURCES = \ pve.cxx pve.hxx \ raw_ctrls.hxx \ ray.cxx ray.hxx \ - rul.cxx rul.hxx + rul.cxx rul.hxx \ + telnet.cxx telnet.hxx if OLD_AUTOMAKE INCLUDES += -I$(top_srcdir) -I$(top_srcdir)/src diff --git a/src/Network/protocol.cxx b/src/Network/protocol.cxx index ea1e66678..be4883ecf 100644 --- a/src/Network/protocol.cxx +++ b/src/Network/protocol.cxx @@ -95,3 +95,14 @@ bool FGProtocol::parse_message() { } +void FGProtocol::set_direction( const string& d ) { + if ( d == "in" ) { + dir = SG_IO_IN; + } else if ( d == "out" ) { + dir = SG_IO_OUT; + } else if ( d == "bi" ) { + dir = SG_IO_BI; + } else { + dir = SG_IO_NONE; + } +} diff --git a/src/Network/protocol.hxx b/src/Network/protocol.hxx index 8c6535b52..4b73d1893 100644 --- a/src/Network/protocol.hxx +++ b/src/Network/protocol.hxx @@ -26,6 +26,7 @@ #include +#include #include STL_STRING #include @@ -36,10 +37,6 @@ SG_USING_STD(vector); #define FG_MAX_MSG_SIZE 16384 -// forward declaration -class SGIOChannel; - - class FGProtocol { private: @@ -68,17 +65,7 @@ public: virtual bool close(); inline SGProtocolDir get_direction() const { return dir; } - inline void set_direction( const string& d ) { - if ( d == "in" ) { - dir = SG_IO_IN; - } else if ( d == "out" ) { - dir = SG_IO_OUT; - } else if ( d == "bi" ) { - dir = SG_IO_BI; - } else { - dir = SG_IO_NONE; - } - } + void set_direction( const string& d ); inline double get_hz() const { return hz; } inline void set_hz( double t ) { hz = t; } @@ -108,6 +95,18 @@ typedef vector < FGProtocol * > io_container; typedef io_container::iterator io_iterator; typedef io_container::const_iterator const_io_iterator; +#include +SG_USING_STD(invalid_argument); + +//namespace flightgear { namespace network { +class FGProtocolConfigError : public invalid_argument +{ +public: + FGProtocolConfigError( const string& what_string ) + : invalid_argument(what_string) {} +}; +//}} // end namespace flightgear::network + #endif // _PROTOCOL_HXX diff --git a/src/Network/telnet.cxx b/src/Network/telnet.cxx new file mode 100644 index 000000000..8af97dbbb --- /dev/null +++ b/src/Network/telnet.cxx @@ -0,0 +1,547 @@ +// \file telnet.cx +// Property telnet server class. +// +// Written by Bernie Bright, started May 2002. +// +// Copyright (C) 2002 Bernie Bright - bbright@bigpond.net.au +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// $Id$ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include STL_STRSTREAM + +#include
+#include
+ +#include + +#include "telnet.hxx" + +#if !defined(SG_HAVE_NATIVE_SGI_COMPILERS) +SG_USING_STD(strstream); +#endif + +/** + * Telnet connection class. + * This class represents a connection to a telnet-style client. + */ +class TelnetChannel : public netChat +{ + netBuffer buffer; + + /** + * Current property node name. + */ + string path; + + enum Mode { + PROMPT, + DATA + }; + Mode mode; + +public: + /** + * Constructor. + */ + TelnetChannel(); + + /** + * Append incoming data to our request buffer. + * + * @param s Character string to append to buffer + * @param n Number of characters to append. + */ + void collectIncomingData( const char* s, int n ); + + /** + * Process a complete request from the telnet client. + */ + void foundTerminator(); + +private: + /** + * Return a "Node no found" error message to the client. + */ + void node_not_found_error( const string& node_name ); + + void view_cmd( const vector& ); +}; + +/** + * + */ +TelnetChannel::TelnetChannel() + : buffer(512), + path("/"), + mode(PROMPT) +{ + setTerminator( "\r\n" ); +} + +/** + * + */ +void +TelnetChannel::collectIncomingData( const char* s, int n ) +{ + buffer.append( s, n ); +} + +/** + * + */ +void +TelnetChannel::node_not_found_error( const string& node_name ) +{ + string error = "ERR Node \""; + error += node_name; + error += "\" not found."; + push( error.c_str() ); + push( getTerminator() ); +} + +// return a human readable form of the value "type" +static string +getValueTypeString( const SGPropertyNode *node ) +{ + string result; + + if ( node == NULL ) + { + return "unknown"; + } + + SGPropertyNode::Type type = node->getType(); + if ( type == SGPropertyNode::UNSPECIFIED ) { + result = "unspecified"; + } else if ( type == SGPropertyNode::NONE ) { + result = "none"; + } else if ( type == SGPropertyNode::BOOL ) { + result = "bool"; + } else if ( type == SGPropertyNode::INT ) { + result = "int"; + } else if ( type == SGPropertyNode::LONG ) { + result = "long"; + } else if ( type == SGPropertyNode::FLOAT ) { + result = "float"; + } else if ( type == SGPropertyNode::DOUBLE ) { + result = "double"; + } else if ( type == SGPropertyNode::STRING ) { + result = "string"; + } + + return result; +} + +/** + * We have a command. + * + * TODO: possible future commands: + * panel + * panel load [path] + * panel mouse