Add client

This commit is contained in:
Keith Winstein
2011-08-13 19:05:11 -04:00
parent 577bfc0dae
commit d6e7f69a4b
8 changed files with 209 additions and 19 deletions
+8 -5
View File
@@ -1,11 +1,11 @@
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 completeterminal.cpp rtm-server.cpp
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 completeterminal.cpp stm-server.cpp stm.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 user.o userinput.pb.o completeterminal.o
repos = templates.rpo
executables = parse termemu ntester encrypt decrypt rtm-server
executables = parse termemu ntester encrypt decrypt stm-server stm
CXX = g++
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
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 -lprotobuf-lite
PROTOC = protoc
@@ -26,8 +26,11 @@ encrypt: encrypt.o $(objects) ntester # serialize link steps because of -frepo
decrypt: decrypt.o $(objects) encrypt # serialize link steps because of -frepo
$(CXX) $(CXXFLAGS) -o $@ decrypt.o $(objects) $(LIBS)
rtm-server: rtm-server.o $(objects) decrypt # serialize link steps because of -frepo
$(CXX) $(CXXFLAGS) -o $@ rtm-server.o $(objects) $(LIBS)
stm-server: stm-server.o $(objects) decrypt # serialize link steps because of -frepo
$(CXX) $(CXXFLAGS) -o $@ stm-server.o $(objects) $(LIBS)
stm: stm.o $(objects) stm-server # serialize link steps because of -frepo
$(CXX) $(CXXFLAGS) -o $@ stm.o $(objects) $(LIBS)
templates.o: templates.cpp
$(CXX) $(CXXFLAGS) -frepo -c -o $@ $<
-3
View File
@@ -18,9 +18,6 @@ namespace Terminal {
std::string act( const std::string &str );
std::string act( const Parser::Action *act );
std::string open( void ) { return terminal.open(); }
std::string close( void ) { return terminal.close(); }
const Framebuffer & get_fb( void ) const { return terminal.get_fb(); }
/* interface for Network::Transport */
+9 -4
View File
@@ -91,7 +91,7 @@ int main( void )
serve( master );
}
printf( "[stm is exiting.]\n" );
printf( "[stm-server is exiting.]\n" );
return 0;
}
@@ -132,8 +132,6 @@ void serve( int host_fd )
uint64_t last_remote_num = network.get_remote_state_num();
while ( 1 ) {
network.set_current_state( terminal );
int active_fds = poll( pollfds, 2, network.tick() );
if ( active_fds < 0 ) {
perror( "poll" );
@@ -155,6 +153,9 @@ void serve( int host_fd )
terminal_to_host += terminal.act( us.get_action( i ) );
}
/* update client with new state of terminal */
network.set_current_state( terminal );
/* write any writeback octets back to the host */
if ( swrite( host_fd, terminal_to_host.c_str(), terminal_to_host.length() ) < 0 ) {
break;
@@ -176,8 +177,12 @@ void serve( int host_fd )
return;
}
/* write any writeback octets back to the host */
string terminal_to_host = terminal.act( string( buf, bytes_read ) );
/* update client with new state of terminal */
network.set_current_state( terminal );
/* write any writeback octets back to the host */
if ( swrite( host_fd, terminal_to_host.c_str(), terminal_to_host.length() ) < 0 ) {
break;
}
+186
View File
@@ -0,0 +1,186 @@
#include <locale.h>
#include <string.h>
#include <langinfo.h>
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <pty.h>
#include <stdlib.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <pwd.h>
#include <signal.h>
#include <sys/signalfd.h>
#include "networktransport.hpp"
#include "completeterminal.hpp"
#include "swrite.hpp"
#include "user.hpp"
void client( const char *ip, int port, const char *key );
using namespace std;
int main( int argc, char *argv[] )
{
/* Get arguments */
char *ip, *key;
int port;
if ( argc != 4 ) {
fprintf( stderr, "Usage: %s IP PORT KEY\n", argv[ 0 ] );
exit( 1 );
}
ip = argv[ 1 ];
port = atoi( argv[ 2 ] );
key = argv[ 3 ];
struct termios saved_termios, raw_termios;
/* Adopt implementation locale */
if ( NULL == setlocale( LC_ALL, "" ) ) {
perror( "setlocale" );
exit( 1 );
}
/* Verify locale calls for UTF-8 */
if ( strcmp( nl_langinfo( CODESET ), "UTF-8" ) != 0 ) {
fprintf( stderr, "stm requires a UTF-8 locale.\n" );
exit( 1 );
}
/* Verify terminal configuration */
if ( tcgetattr( STDIN_FILENO, &saved_termios ) < 0 ) {
perror( "tcgetattr" );
exit( 1 );
}
/* Put terminal driver in raw mode */
raw_termios = saved_termios;
if ( !(raw_termios.c_iflag & IUTF8) ) {
fprintf( stderr, "Warning: Locale is UTF-8 but termios IUTF8 flag not set. Setting IUTF8 flag.\n" );
raw_termios.c_iflag |= IUTF8;
}
cfmakeraw( &raw_termios );
if ( tcsetattr( STDIN_FILENO, TCSANOW, &raw_termios ) < 0 ) {
perror( "tcsetattr" );
exit( 1 );
}
/* Put terminal in application-cursor-key mode */
swrite( STDOUT_FILENO, Terminal::Emulator::open().c_str() );
client( ip, port, key );
/* Restore terminal and terminal-driver state */
swrite( STDOUT_FILENO, Terminal::Emulator::close().c_str() );
if ( tcsetattr( STDIN_FILENO, TCSANOW, &saved_termios ) < 0 ) {
perror( "tcsetattr" );
exit( 1 );
}
printf( "[stm is exiting.]\n" );
return 0;
}
void client( const char *ip, int port, const char *key )
{
/* establish WINCH fd and start listening for signal */
sigset_t signal_mask;
assert( sigemptyset( &signal_mask ) == 0 );
assert( sigaddset( &signal_mask, SIGWINCH ) == 0 );
/* stop "ignoring" WINCH signal */
assert( sigprocmask( SIG_BLOCK, &signal_mask, NULL ) == 0 );
int winch_fd = signalfd( -1, &signal_mask, 0 );
if ( winch_fd < 0 ) {
perror( "signalfd" );
return;
}
/* get initial window size */
struct winsize window_size;
if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 ) {
perror( "ioctl TIOCGWINSZ" );
return;
}
/* XXX transmit initial resize */
/* local state */
Terminal::Complete terminal( window_size.ws_col, window_size.ws_row );
Terminal::Framebuffer state( window_size.ws_col, window_size.ws_row );
/* open network */
Network::UserStream blank;
Network::Transport< Network::UserStream, Terminal::Complete > network( blank, terminal,
key, ip, port );
/* prepare to poll for events */
struct pollfd pollfds[ 3 ];
pollfds[ 0 ].fd = network.fd();
pollfds[ 0 ].events = POLLIN;
pollfds[ 1 ].fd = STDIN_FILENO;
pollfds[ 1 ].events = POLLIN;
pollfds[ 2 ].fd = winch_fd;
pollfds[ 2 ].events = POLLIN;
uint64_t last_remote_num = network.get_remote_state_num();
while ( 1 ) {
int active_fds = poll( pollfds, 3, network.tick() );
if ( active_fds < 0 ) {
perror( "poll" );
break;
}
if ( pollfds[ 0 ].revents & POLLIN ) {
/* packet received from the network */
network.recv();
/* is a new frame available from the terminal? */
if ( network.get_remote_state_num() != last_remote_num ) {
string diff = network.get_remote_diff();
swrite( STDOUT_FILENO, diff.data(), diff.size() );
}
}
if ( pollfds[ 1 ].revents & POLLIN ) {
/* input from the user needs to be fed to the network */
const int buf_size = 16384;
char buf[ buf_size ];
/* fill buffer if possible */
ssize_t bytes_read = read( pollfds[ 1 ].fd, buf, buf_size );
if ( bytes_read == 0 ) { /* EOF */
return;
} else if ( bytes_read < 0 ) {
perror( "read" );
return;
}
for ( int i = 0; i < bytes_read; i++ ) {
network.get_current_state().push_back( Parser::UserByte( buf[ i ] ) );
}
}
if ( pollfds[ 2 ].revents & POLLIN ) {
/* handle resize */
}
if ( (pollfds[ 0 ].revents | pollfds[ 1 ].revents)
& (POLLERR | POLLHUP | POLLNVAL) ) {
break;
}
}
}
+1
View File
@@ -31,5 +31,6 @@ template class vector<bool>;
template class vector<Instruction>;
template class Transport<UserStream, UserStream>;
template class Transport<Complete, UserStream>;
template class Transport<UserStream, Complete>;
template class deque<UserEvent>;
+2 -2
View File
@@ -208,7 +208,7 @@ void emulate_terminal( int fd )
pollfds[ 2 ].fd = winch_fd;
pollfds[ 2 ].events = POLLIN;
swrite( STDOUT_FILENO, complete.open().c_str() );
swrite( STDOUT_FILENO, Terminal::Emulator::open().c_str() );
int poll_timeout = -1;
@@ -295,5 +295,5 @@ void emulate_terminal( int fd )
std::string update = Terminal::Display::new_frame( true, state, complete.get_fb() );
swrite( STDOUT_FILENO, update.c_str() );
swrite( STDOUT_FILENO, complete.close().c_str() );
swrite( STDOUT_FILENO, Terminal::Emulator::close().c_str() );
}
+1 -3
View File
@@ -155,7 +155,5 @@ void Emulator::resize( size_t s_width, size_t s_height )
bool Emulator::operator==( Emulator const &x ) const
{
assert( dispatch == x.dispatch );
assert( user == x.user );
return fb == x.fb;
return ( dispatch == x.dispatch ) && ( user == x.user ) && ( fb == x.fb );
}
+2 -2
View File
@@ -46,8 +46,8 @@ namespace Terminal {
std::string read_octets_to_host( void );
std::string open( void ); /* put user cursor keys in application mode */
std::string close( void ); /* restore user cursor keys */
static std::string open( void ); /* put user cursor keys in application mode */
static std::string close( void ); /* restore user cursor keys */
const Framebuffer & get_fb( void ) const { return fb; }