diff --git a/Makefile b/Makefile index 765d83e..c29ff78 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,13 @@ -source = parse.cpp parserstate.cpp parser.cpp templates.cpp terminal.cpp termemu.cpp parseraction.cpp terminalfunctions.cpp swrite.cpp terminalframebuffer.cpp terminaldispatcher.cpp terminaluserinput.cpp terminaldisplay.cpp network.cpp ntester.cpp ocb.cpp base64.cpp encrypt.cpp decrypt.cpp crypto.cpp networktransport.cpp networkinstruction.cpp keystroke.cpp -objects = parserstate.o parser.o templates.o terminal.o parseraction.o terminalfunctions.o swrite.o terminalframebuffer.o terminaldispatcher.o terminaluserinput.o terminaldisplay.o network.o ocb.o base64.o crypto.o networktransport.o networkinstruction.o keystroke.o +proto = userinput.proto +source = parse.cpp parserstate.cpp parser.cpp templates.cpp terminal.cpp termemu.cpp parseraction.cpp terminalfunctions.cpp swrite.cpp terminalframebuffer.cpp terminaldispatcher.cpp terminaluserinput.cpp terminaldisplay.cpp network.cpp ntester.cpp ocb.cpp base64.cpp encrypt.cpp decrypt.cpp crypto.cpp networktransport.cpp networkinstruction.cpp user.cpp userinput.pb.cc +objects = parserstate.o parser.o templates.o terminal.o parseraction.o terminalfunctions.o swrite.o terminalframebuffer.o terminaldispatcher.o terminaluserinput.o terminaldisplay.o network.o ocb.o base64.o crypto.o networktransport.o networkinstruction.o user.o userinput.pb.o repos = templates.rpo executables = parse termemu ntester encrypt decrypt CXX = g++ -CXXFLAGS = -g -O2 --std=c++0x -pedantic -Werror -Wall -Wextra -Weffc++ -fno-implicit-templates -fno-default-inline -pipe -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=500 -D_GNU_SOURCE -D_BSD_SOURCE -LIBS = -lutil -lssl -lrt -lm +CXXFLAGS = -g --std=c++0x -pedantic -Werror -Wall -Wextra -Weffc++ -fno-implicit-templates -fno-default-inline -pipe -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=500 -D_GNU_SOURCE -D_BSD_SOURCE +LIBS = -lutil -lssl -lrt -lm -lprotobuf-lite +PROTOC = protoc all: $(executables) @@ -30,6 +32,12 @@ templates.o: templates.cpp %.o: %.cpp $(CXX) $(CXXFLAGS) -c -o $@ $< +%.pb.cc: %.proto + $(PROTOC) --cpp_out=. $< + +%.pb.o: %.pb.cc + $(CXX) $(CXXFLAGS) -frepo -Wno-effc++ -c -o $@ $< + -include depend depend: $(source) @@ -37,4 +45,4 @@ depend: $(source) .PHONY: clean clean: - -rm -f $(executables) depend *.o *.rpo + -rm -f $(executables) depend *.o *.rpo *.pb.cc *.pb.h diff --git a/keystroke.cpp b/keystroke.cpp deleted file mode 100644 index 20e4f54..0000000 --- a/keystroke.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include - -#include "keystroke.hpp" - -void KeyStroke::subtract( KeyStroke * const prefix ) -{ - for ( deque::iterator i = prefix->user_bytes.begin(); - i != prefix->user_bytes.end(); - i++ ) { - assert( !user_bytes.empty() ); - assert( *i == user_bytes.front() ); - user_bytes.pop_front(); - } -} - -string KeyStroke::diff_from( KeyStroke const & existing ) -{ - string ret; - - deque::iterator my_it = user_bytes.begin(); - - for ( deque::const_iterator i = existing.user_bytes.begin(); - i != existing.user_bytes.end(); - i++ ) { - assert( my_it != user_bytes.end() ); - if ( *i != *my_it ) { - fprintf( stderr, "BUG: existing state has %c and new state has %c\n", - *i, *my_it ); - } - assert( *i == *my_it ); - my_it++; - } - - while ( my_it != user_bytes.end() ) { - ret += string( &( *my_it ), 1 ); - my_it++; - } - - return ret; -} - -void KeyStroke::apply_string( string diff ) -{ - for ( string::iterator i = diff.begin(); - i != diff.end(); - i++ ) { - user_bytes.push_back( *i ); - } -} diff --git a/keystroke.hpp b/keystroke.hpp deleted file mode 100644 index 26a4aee..0000000 --- a/keystroke.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef KEYSTROKE_HPP -#define KEYSTROKE_HPP - -#include -#include -#include - -using namespace std; - -class KeyStroke -{ -public: - deque user_bytes; - - KeyStroke() : user_bytes() {} - - void key_hit( char x ) { user_bytes.push_back( x ); } - - /* interface for Network::Transport */ - void subtract( KeyStroke * const prefix ); - string diff_from( KeyStroke const & existing ); - void apply_string( string diff ); - bool operator==( KeyStroke const &x ) const { return user_bytes == x.user_bytes; } -}; - -#endif diff --git a/networktransport.cpp b/networktransport.cpp index f0ea2cb..9256678 100644 --- a/networktransport.cpp +++ b/networktransport.cpp @@ -75,6 +75,8 @@ void Transport::send_to_receiver( void ) return; } + /* XXX should increment number each time */ + Instruction inst( assumed_receiver_state->num, assumed_receiver_state->num, received_states.back().num, diff --git a/ntester.cpp b/ntester.cpp index 718e2e5..ea41d4c 100644 --- a/ntester.cpp +++ b/ntester.cpp @@ -2,9 +2,11 @@ #include #include -#include "keystroke.hpp" +#include "user.hpp" #include "networktransport.hpp" +using namespace Network; + int main( int argc, char *argv[] ) { bool server = true; @@ -12,9 +14,9 @@ int main( int argc, char *argv[] ) char *ip; int port; - KeyStroke me, remote; + UserStream me, remote; - Network::Transport *n; + Transport *n; try { if ( argc > 1 ) { @@ -25,9 +27,9 @@ int main( int argc, char *argv[] ) ip = argv[ 2 ]; port = atoi( argv[ 3 ] ); - n = new Network::Transport( me, remote, key, ip, port ); + n = new Transport( me, remote, key, ip, port ); } else { - n = new Network::Transport( me, remote ); + n = new Transport( me, remote ); } } catch ( CryptoException e ) { fprintf( stderr, "Fatal error: %s\n", e.text.c_str() ); @@ -94,13 +96,13 @@ int main( int argc, char *argv[] ) if ( fds[ 0 ].revents & POLLIN ) { char x; assert( read( STDIN_FILENO, &x, 1 ) == 1 ); - n->get_current_state().key_hit( x ); + n->get_current_state().push_back( Parser::UserByte( x ) ); } if ( fds[ 1 ].revents & POLLIN ) { n->recv(); } - } catch ( Network::NetworkException e ) { + } catch ( NetworkException e ) { fprintf( stderr, "%s: %s\r\n", e.function.c_str(), strerror( e.the_errno ) ); break; } catch ( CryptoException e ) { diff --git a/parseraction.cpp b/parseraction.cpp index 097f6fc..f5fdf12 100644 --- a/parseraction.cpp +++ b/parseraction.cpp @@ -80,3 +80,10 @@ void Resize::act_on_terminal( Terminal::Emulator *emu ) emu->resize( width, height ); handled = true; } + +bool Action::operator==( const Action &other ) const +{ + return ( char_present == other.char_present ) + && ( ch == other.ch ) + && ( handled == other.handled ); +} diff --git a/parseraction.hpp b/parseraction.hpp index 3a644e9..7709b69 100644 --- a/parseraction.hpp +++ b/parseraction.hpp @@ -23,6 +23,8 @@ namespace Parser { Action() : char_present( false ), ch( -1 ), handled( false ) {}; virtual ~Action() {}; + + virtual bool operator==( const Action &other ) const; }; class Ignore : public Action { @@ -97,6 +99,11 @@ namespace Parser { void act_on_terminal( Terminal::Emulator *emu ); UserByte( int s_c ) : c( s_c ) {} + + bool operator==( const UserByte &other ) const + { + return c == other.c; + } }; class Resize : public Action { @@ -111,6 +118,11 @@ namespace Parser { : width( s_width ), height( s_height ) {} + + bool operator==( const Resize &other ) const + { + return ( width == other.width ) && ( height == other.height ); + } }; } diff --git a/templates.cpp b/templates.cpp index 1c0c930..66ee288 100644 --- a/templates.cpp +++ b/templates.cpp @@ -6,8 +6,9 @@ #include "terminal.hpp" -#include "keystroke.hpp" +#include "user.hpp" #include "networktransport.cpp" +#include "userinput.pb.h" namespace Parser { class Action; @@ -15,6 +16,7 @@ namespace Parser { using namespace std; using namespace Terminal; +using namespace Network; template class list; template class vector; @@ -24,7 +26,8 @@ template class vector; template class vector; template class map; template class vector; -template class deque; -template class vector; -template class Network::Transport; +template class vector; +template class Transport; + +template class deque; diff --git a/user.cpp b/user.cpp new file mode 100644 index 0000000..8e1755d --- /dev/null +++ b/user.cpp @@ -0,0 +1,85 @@ +#include +#include + +#include "user.hpp" +#include "userinput.pb.h" + +using namespace Parser; +using namespace Network; +using namespace ClientBuffers; + +void UserStream::subtract( UserStream * const prefix ) +{ + for ( deque::iterator i = prefix->actions.begin(); + i != prefix->actions.end(); + i++ ) { + assert( !actions.empty() ); + assert( *i == actions.front() ); + actions.pop_front(); + } +} + +string UserStream::diff_from( UserStream const & existing ) +{ + deque::iterator my_it = actions.begin(); + + for ( deque::const_iterator i = existing.actions.begin(); + i != existing.actions.end(); + i++ ) { + assert( my_it != actions.end() ); + assert( *i == *my_it ); + my_it++; + } + + ClientBuffers::UserMessage output; + + while ( my_it != actions.end() ) { + switch ( my_it->type ) { + case UserByteType: + { + char the_byte = my_it->userbyte.c; + /* can we combine this with a previous Keystroke? */ + if ( (output.instruction_size() > 0) + && (output.instruction( output.instruction_size() - 1 ).HasExtension( keystroke )) ) { + output.mutable_instruction( output.instruction_size() - 1 )->MutableExtension( keystroke )->mutable_keys()->append( string( &the_byte, 1 ) ); + } else { + Instruction *new_inst = output.add_instruction(); + new_inst->MutableExtension( keystroke )->set_keys( &the_byte, 1 ); + } + } + break; + case ResizeType: + { + Instruction *new_inst = output.add_instruction(); + new_inst->MutableExtension( resize )->set_width( my_it->resize.width ); + new_inst->MutableExtension( resize )->set_height( my_it->resize.height ); + } + break; + default: + assert( false ); + } + + my_it++; + } + + return output.SerializeAsString(); +} + +void UserStream::apply_string( string diff ) +{ + ClientBuffers::UserMessage input; + assert( input.ParseFromString( diff ) ); + + for ( int i = 0; i < input.instruction_size(); i++ ) { + if ( input.instruction( i ).HasExtension( keystroke ) ) { + string the_bytes = input.instruction( i ).GetExtension( keystroke ).keys(); + for ( unsigned int loc = 0; loc < the_bytes.size(); loc++ ) { + actions.push_back( UserEvent( UserByte( the_bytes.at( loc ) ) ) ); + } + } else if ( input.instruction( i ).HasExtension( resize ) ) { + actions.push_back( UserEvent( Resize( input.instruction( i ).GetExtension( resize ).width(), + input.instruction( i ).GetExtension( resize ).height() ) ) ); + } + } +} + diff --git a/user.hpp b/user.hpp new file mode 100644 index 0000000..cea00c2 --- /dev/null +++ b/user.hpp @@ -0,0 +1,53 @@ +#ifndef USER_HPP +#define USER_HPP + +#include +#include +#include +#include + +#include "parseraction.hpp" + +using namespace std; + +namespace Network { + enum UserEventType { + UserByteType = 0, + ResizeType = 1 + }; + + class UserEvent + { + public: + UserEventType type; + Parser::UserByte userbyte; + Parser::Resize resize; + + UserEvent( Parser::UserByte s_userbyte ) : type( UserByteType ), userbyte( s_userbyte ), resize( -1, -1 ) {} + UserEvent( Parser::Resize s_resize ) : type( ResizeType ), userbyte( 0 ), resize( s_resize ) {} + + bool operator==( const UserEvent &x ) const { return ( type == x.type ) && ( userbyte == x.userbyte ) && ( resize == x.resize ); } + }; + + class UserStream + { + private: + deque actions; + + public: + UserStream() : actions() {} + + void push_back( Parser::UserByte s_userbyte ) { actions.push_back( UserEvent( s_userbyte ) ); } + void push_back( Parser::Resize s_resize ) { actions.push_back( UserEvent( s_resize ) ); } + + list get_actions( void ); + + /* interface for Network::Transport */ + void subtract( UserStream * const prefix ); + string diff_from( UserStream const & existing ); + void apply_string( string diff ); + bool operator==( UserStream const &x ) const { return actions == x.actions; } + }; +} + +#endif diff --git a/userinput.proto b/userinput.proto new file mode 100644 index 0000000..32bceca --- /dev/null +++ b/userinput.proto @@ -0,0 +1,25 @@ +option optimize_for = LITE_RUNTIME; + +package ClientBuffers; + +message UserMessage { + repeated Instruction instruction = 1; +} + +message Instruction { + extensions 2 to max; +} + +message Keystroke { + optional bytes keys = 4; +} + +message ResizeMessage { + optional int32 width = 5; + optional int32 height = 6; +} + +extend Instruction { + optional Keystroke keystroke = 2; + optional ResizeMessage resize = 3; +}