Make examples compileable
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
SUBDIRS = protobufs util crypto terminal network statesync frontend
|
||||
SUBDIRS = protobufs util crypto terminal network statesync frontend examples
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
AM_CXXFLAGS = --std=c++0x -pedantic -Werror -Wall -Wextra -Weffc++ -fno-default-inline -pipe
|
||||
|
||||
noinst_PROGRAMS = encrypt decrypt ntester parse termemu
|
||||
|
||||
LIBS = `pkg-config --libs protobuf-lite`
|
||||
|
||||
encrypt_SOURCES = encrypt.cc
|
||||
encrypt_CPPFLAGS = -I$(srcdir)/../crypto
|
||||
encrypt_LDADD = ../crypto/libmoshcrypto.a
|
||||
|
||||
decrypt_SOURCES = decrypt.cc
|
||||
decrypt_CPPFLAGS = -I$(srcdir)/../crypto
|
||||
decrypt_LDADD = ../crypto/libmoshcrypto.a
|
||||
|
||||
parse_SOURCES = parse.cc
|
||||
parse_CPPFLAGS = -I$(srcdir)/../terminal -I$(srcdir)/../util
|
||||
parse_LDADD = ../terminal/libmoshterminal.a ../util/libmoshutil.a -lutil
|
||||
|
||||
termemu_SOURCES = termemu.cc
|
||||
termemu_CPPFLAGS = -I$(srcdir)/../terminal -I$(srcdir)/../util -I$(srcdir)/../statesync -I$(builddir)/../protobufs
|
||||
termemu_LDADD = ../terminal/libmoshterminal.a ../util/libmoshutil.a ../statesync/libmoshstatesync.a ../protobufs/libmoshprotos.a -lutil
|
||||
|
||||
ntester_SOURCES = ntester.cc
|
||||
ntester_CPPFLAGS = -I$(srcdir)/../statesync -I$(srcdir)/../terminal -I$(srcdir)/../network -I$(srcdir)/../crypto -I$(builddir)/../protobufs
|
||||
ntester_LDADD = ../statesync/libmoshstatesync.a ../terminal/libmoshterminal.a ../network/libmoshnetwork.a ../crypto/libmoshcrypto.a ../protobufs/libmoshprotos.a -lutil -lrt -lm
|
||||
@@ -0,0 +1,60 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
using namespace Crypto;
|
||||
|
||||
int main( int argc, char *argv[] )
|
||||
{
|
||||
if ( argc != 2 ) {
|
||||
fprintf( stderr, "Usage: %s KEY\n", argv[ 0 ] );
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
Base64Key key( argv[ 1 ] );
|
||||
Session session( key );
|
||||
|
||||
/* Read input */
|
||||
char *input = NULL;
|
||||
int total_size = 0;
|
||||
|
||||
while ( 1 ) {
|
||||
unsigned char buf[ 16384 ];
|
||||
ssize_t bytes_read = read( STDIN_FILENO, buf, 16384 );
|
||||
if ( bytes_read == 0 ) { /* EOF */
|
||||
break;
|
||||
} else if ( bytes_read < 0 ) {
|
||||
perror( "read" );
|
||||
exit( 1 );
|
||||
} else {
|
||||
input = (char *)realloc( input, total_size + bytes_read );
|
||||
assert( input );
|
||||
memcpy( input + total_size, buf, bytes_read );
|
||||
total_size += bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
string ciphertext( input, total_size );
|
||||
free( input );
|
||||
|
||||
/* Decrypt message */
|
||||
|
||||
Message message = session.decrypt( ciphertext );
|
||||
|
||||
fprintf( stderr, "Nonce = %ld\n",
|
||||
(long)message.nonce.val() );
|
||||
cout << message.text;
|
||||
} catch ( CryptoException e ) {
|
||||
cerr << e.text << endl;
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
using namespace Crypto;
|
||||
|
||||
int main( int argc, char *argv[] )
|
||||
{
|
||||
if ( argc != 2 ) {
|
||||
fprintf( stderr, "Usage: %s NONCE\n", argv[ 0 ] );
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
Base64Key key;
|
||||
Session session( key );
|
||||
Nonce nonce( myatoi( argv[ 1 ] ) );
|
||||
|
||||
/* Read input */
|
||||
char *input = NULL;
|
||||
int total_size = 0;
|
||||
|
||||
while ( 1 ) {
|
||||
unsigned char buf[ 16384 ];
|
||||
ssize_t bytes_read = read( STDIN_FILENO, buf, 16384 );
|
||||
if ( bytes_read == 0 ) { /* EOF */
|
||||
break;
|
||||
} else if ( bytes_read < 0 ) {
|
||||
perror( "read" );
|
||||
exit( 1 );
|
||||
} else {
|
||||
input = (char *)realloc( input, total_size + bytes_read );
|
||||
assert( input );
|
||||
memcpy( input + total_size, buf, bytes_read );
|
||||
total_size += bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
string plaintext( input, total_size );
|
||||
free( input );
|
||||
|
||||
/* Encrypt message */
|
||||
|
||||
string ciphertext = session.encrypt( Message( nonce, plaintext ) );
|
||||
|
||||
cerr << "Key: " << key.printable_key() << endl;
|
||||
|
||||
cout << ciphertext;
|
||||
} catch ( CryptoException e ) {
|
||||
cerr << e.text << endl;
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include "user.h"
|
||||
#include "networktransport.cc"
|
||||
|
||||
using namespace Network;
|
||||
|
||||
int main( int argc, char *argv[] )
|
||||
{
|
||||
bool server = true;
|
||||
char *key;
|
||||
char *ip;
|
||||
int port;
|
||||
|
||||
UserStream me, remote;
|
||||
|
||||
Transport<UserStream, UserStream> *n;
|
||||
|
||||
try {
|
||||
if ( argc > 1 ) {
|
||||
server = false;
|
||||
/* client */
|
||||
|
||||
key = argv[ 1 ];
|
||||
ip = argv[ 2 ];
|
||||
port = atoi( argv[ 3 ] );
|
||||
|
||||
n = new Transport<UserStream, UserStream>( me, remote, key, ip, port );
|
||||
} else {
|
||||
n = new Transport<UserStream, UserStream>( me, remote, NULL );
|
||||
}
|
||||
} catch ( CryptoException e ) {
|
||||
fprintf( stderr, "Fatal error: %s\n", e.text.c_str() );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
fprintf( stderr, "Port bound is %d, key is %s\n", n->port(), n->get_key().c_str() );
|
||||
|
||||
if ( server ) {
|
||||
struct pollfd my_pollfd;
|
||||
my_pollfd.fd = n->fd();
|
||||
my_pollfd.events = POLLIN;
|
||||
uint64_t last_num = n->get_remote_state_num();
|
||||
while ( true ) {
|
||||
try {
|
||||
if ( poll( &my_pollfd, 1, n->wait_time() ) < 0 ) {
|
||||
perror( "poll" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
n->tick();
|
||||
|
||||
if ( my_pollfd.revents & POLLIN ) {
|
||||
n->recv();
|
||||
|
||||
if ( n->get_remote_state_num() != last_num ) {
|
||||
fprintf( stderr, "[%d=>%d %s]", (int)last_num, (int)n->get_remote_state_num(), n->get_remote_diff().c_str() );
|
||||
last_num = n->get_remote_state_num();
|
||||
}
|
||||
}
|
||||
} catch ( CryptoException e ) {
|
||||
fprintf( stderr, "Cryptographic error: %s\n", e.text.c_str() );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
struct termios saved_termios;
|
||||
struct termios the_termios;
|
||||
|
||||
if ( tcgetattr( STDIN_FILENO, &the_termios ) < 0 ) {
|
||||
perror( "tcgetattr" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
saved_termios = the_termios;
|
||||
|
||||
cfmakeraw( &the_termios );
|
||||
|
||||
if ( tcsetattr( STDIN_FILENO, TCSANOW, &the_termios ) < 0 ) {
|
||||
perror( "tcsetattr" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
struct pollfd fds[ 2 ];
|
||||
fds[ 0 ].fd = STDIN_FILENO;
|
||||
fds[ 0 ].events = POLLIN;
|
||||
|
||||
fds[ 1 ].fd = n->fd();
|
||||
fds[ 1 ].events = POLLIN;
|
||||
|
||||
while( true ) {
|
||||
try {
|
||||
if ( poll( fds, 2, n->wait_time() ) < 0 ) {
|
||||
perror( "poll" );
|
||||
}
|
||||
|
||||
n->tick();
|
||||
|
||||
if ( fds[ 0 ].revents & POLLIN ) {
|
||||
char x;
|
||||
assert( read( STDIN_FILENO, &x, 1 ) == 1 );
|
||||
n->get_current_state().push_back( Parser::UserByte( x ) );
|
||||
}
|
||||
|
||||
if ( fds[ 1 ].revents & POLLIN ) {
|
||||
n->recv();
|
||||
}
|
||||
} catch ( NetworkException e ) {
|
||||
fprintf( stderr, "%s: %s\r\n", e.function.c_str(), strerror( e.the_errno ) );
|
||||
break;
|
||||
} catch ( CryptoException e ) {
|
||||
fprintf( stderr, "Cryptographic error: %s\n", e.text.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
if ( tcsetattr( STDIN_FILENO, TCSANOW, &saved_termios ) < 0 ) {
|
||||
perror( "tcsetattr" );
|
||||
exit( 1 );
|
||||
}
|
||||
}
|
||||
|
||||
delete n;
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
#include <pty.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
#include <langinfo.h>
|
||||
#include <wchar.h>
|
||||
#include <assert.h>
|
||||
#include <wctype.h>
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "parser.h"
|
||||
#include "swrite.h"
|
||||
|
||||
const size_t buf_size = 1024;
|
||||
|
||||
void emulate_terminal( int fd );
|
||||
int copy( int src, int dest );
|
||||
int vt_parser( int fd, Parser::UTF8Parser *parser );
|
||||
|
||||
int main( int argc __attribute__((unused)),
|
||||
char *argv[] __attribute__((unused)),
|
||||
char *envp[] )
|
||||
{
|
||||
int master;
|
||||
struct termios saved_termios, raw_termios, child_termios;
|
||||
|
||||
if ( NULL == setlocale( LC_ALL, "" ) ) {
|
||||
perror( "setlocale" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
if ( strcmp( nl_langinfo( CODESET ), "UTF-8" ) != 0 ) {
|
||||
fprintf( stderr, "stm requires a UTF-8 locale.\n" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
if ( tcgetattr( STDIN_FILENO, &saved_termios ) < 0 ) {
|
||||
perror( "tcgetattr" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
child_termios = saved_termios;
|
||||
|
||||
if ( !(child_termios.c_iflag & IUTF8) ) {
|
||||
fprintf( stderr, "Warning: Locale is UTF-8 but termios IUTF8 flag not set. Setting IUTF8 flag.\n" );
|
||||
child_termios.c_iflag |= IUTF8;
|
||||
}
|
||||
|
||||
pid_t child = forkpty( &master, NULL, &child_termios, NULL );
|
||||
|
||||
if ( child == -1 ) {
|
||||
perror( "forkpty" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
if ( child == 0 ) {
|
||||
/* child */
|
||||
char *my_argv[ 2 ];
|
||||
my_argv[ 0 ] = strdup( "/bin/bash" );
|
||||
assert( my_argv[ 0 ] );
|
||||
|
||||
my_argv[ 1 ] = NULL;
|
||||
|
||||
if ( execve( "/bin/bash", my_argv, envp ) < 0 ) {
|
||||
perror( "execve" );
|
||||
exit( 1 );
|
||||
}
|
||||
exit( 0 );
|
||||
} else {
|
||||
/* parent */
|
||||
raw_termios = saved_termios;
|
||||
|
||||
cfmakeraw( &raw_termios );
|
||||
|
||||
if ( tcsetattr( STDIN_FILENO, TCSANOW, &raw_termios ) < 0 ) {
|
||||
perror( "tcsetattr" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
emulate_terminal( master );
|
||||
|
||||
if ( tcsetattr( STDIN_FILENO, TCSANOW, &saved_termios ) < 0 ) {
|
||||
perror( "tcsetattr" );
|
||||
exit( 1 );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void emulate_terminal( int fd )
|
||||
{
|
||||
Parser::UTF8Parser parser;
|
||||
struct pollfd pollfds[ 2 ];
|
||||
|
||||
pollfds[ 0 ].fd = STDIN_FILENO;
|
||||
pollfds[ 0 ].events = POLLIN;
|
||||
|
||||
pollfds[ 1 ].fd = fd;
|
||||
pollfds[ 1 ].events = POLLIN;
|
||||
|
||||
while ( 1 ) {
|
||||
int active_fds = poll( pollfds, 2, -1 );
|
||||
if ( active_fds <= 0 ) {
|
||||
perror( "poll" );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( pollfds[ 0 ].revents & POLLIN ) {
|
||||
if ( copy( STDIN_FILENO, fd ) < 0 ) {
|
||||
return;
|
||||
}
|
||||
} else if ( pollfds[ 1 ].revents & POLLIN ) {
|
||||
if ( vt_parser( fd, &parser ) < 0 ) {
|
||||
return;
|
||||
}
|
||||
} else if ( (pollfds[ 0 ].revents | pollfds[ 1 ].revents)
|
||||
& (POLLERR | POLLHUP | POLLNVAL) ) {
|
||||
return;
|
||||
} else {
|
||||
fprintf( stderr, "poll mysteriously woken up\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int copy( int src, int dest )
|
||||
{
|
||||
char buf[ buf_size ];
|
||||
|
||||
ssize_t bytes_read = read( src, buf, buf_size );
|
||||
if ( bytes_read == 0 ) { /* EOF */
|
||||
return -1;
|
||||
} else if ( bytes_read < 0 ) {
|
||||
perror( "read" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return swrite( dest, buf, bytes_read );
|
||||
}
|
||||
|
||||
int vt_parser( int fd, Parser::UTF8Parser *parser )
|
||||
{
|
||||
char buf[ buf_size ];
|
||||
|
||||
/* fill buffer if possible */
|
||||
ssize_t bytes_read = read( fd, buf, buf_size );
|
||||
if ( bytes_read == 0 ) { /* EOF */
|
||||
return -1;
|
||||
} else if ( bytes_read < 0 ) {
|
||||
perror( "read" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* feed to parser */
|
||||
for ( int i = 0; i < bytes_read; i++ ) {
|
||||
std::list<Parser::Action *> actions = parser->input( buf[ i ] );
|
||||
for ( std::list<Parser::Action *>::iterator j = actions.begin();
|
||||
j != actions.end();
|
||||
j++ ) {
|
||||
|
||||
Parser::Action *act = *j;
|
||||
assert( act );
|
||||
|
||||
if ( act->char_present ) {
|
||||
if ( iswprint( act->ch ) ) {
|
||||
printf( "%s(0x%02x=%lc) ", act->name().c_str(), act->ch, act->ch );
|
||||
} else {
|
||||
printf( "%s(0x%02x) ", act->name().c_str(), act->ch );
|
||||
}
|
||||
} else {
|
||||
printf( "[%s] ", act->name().c_str() );
|
||||
}
|
||||
|
||||
delete act;
|
||||
|
||||
fflush( stdout );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
#include <pty.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
#include <langinfo.h>
|
||||
#include <wchar.h>
|
||||
#include <assert.h>
|
||||
#include <wctype.h>
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <termios.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "parser.h"
|
||||
#include "completeterminal.h"
|
||||
#include "swrite.h"
|
||||
|
||||
const size_t buf_size = 16384;
|
||||
|
||||
void emulate_terminal( int fd );
|
||||
|
||||
int main( void )
|
||||
{
|
||||
int master;
|
||||
struct termios saved_termios, raw_termios, child_termios;
|
||||
|
||||
if ( NULL == setlocale( LC_ALL, "" ) ) {
|
||||
perror( "setlocale" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
if ( strcmp( nl_langinfo( CODESET ), "UTF-8" ) != 0 ) {
|
||||
fprintf( stderr, "stm requires a UTF-8 locale.\n" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
if ( tcgetattr( STDIN_FILENO, &saved_termios ) < 0 ) {
|
||||
perror( "tcgetattr" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
child_termios = saved_termios;
|
||||
|
||||
if ( !(child_termios.c_iflag & IUTF8) ) {
|
||||
fprintf( stderr, "Warning: Locale is UTF-8 but termios IUTF8 flag not set. Setting IUTF8 flag.\n" );
|
||||
child_termios.c_iflag |= IUTF8;
|
||||
}
|
||||
|
||||
pid_t child = forkpty( &master, NULL, &child_termios, NULL );
|
||||
|
||||
if ( child == -1 ) {
|
||||
perror( "forkpty" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
if ( child == 0 ) {
|
||||
/* child */
|
||||
if ( setenv( "TERM", "xterm", true ) < 0 ) {
|
||||
perror( "setenv" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
/* ask ncurses to send UTF-8 instead of ISO 2022 for line-drawing chars */
|
||||
if ( setenv( "NCURSES_NO_UTF8_ACS", "1", true ) < 0 ) {
|
||||
perror( "setenv" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
/* get shell name */
|
||||
struct passwd *pw = getpwuid( geteuid() );
|
||||
if ( pw == NULL ) {
|
||||
perror( "getpwuid" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
char *my_argv[ 2 ];
|
||||
my_argv[ 0 ] = strdup( pw->pw_shell );
|
||||
assert( my_argv[ 0 ] );
|
||||
my_argv[ 1 ] = NULL;
|
||||
|
||||
if ( execve( pw->pw_shell, my_argv, environ ) < 0 ) {
|
||||
perror( "execve" );
|
||||
exit( 1 );
|
||||
}
|
||||
exit( 0 );
|
||||
} else {
|
||||
/* parent */
|
||||
raw_termios = saved_termios;
|
||||
|
||||
cfmakeraw( &raw_termios );
|
||||
|
||||
if ( tcsetattr( STDIN_FILENO, TCSANOW, &raw_termios ) < 0 ) {
|
||||
perror( "tcsetattr" );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
emulate_terminal( master );
|
||||
|
||||
if ( tcsetattr( STDIN_FILENO, TCSANOW, &saved_termios ) < 0 ) {
|
||||
perror( "tcsetattr" );
|
||||
exit( 1 );
|
||||
}
|
||||
}
|
||||
|
||||
printf( "[stm is exiting.]\n" );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Print a frame if the last frame was more than 1/50 seconds ago */
|
||||
bool tick( Terminal::Framebuffer &state, const Terminal::Framebuffer &new_frame )
|
||||
{
|
||||
static bool initialized = false;
|
||||
static struct timeval last_time;
|
||||
|
||||
struct timeval this_time;
|
||||
|
||||
if ( gettimeofday( &this_time, NULL ) < 0 ) {
|
||||
perror( "gettimeofday" );
|
||||
}
|
||||
|
||||
double diff = (this_time.tv_sec - last_time.tv_sec)
|
||||
+ .000001 * (this_time.tv_usec - last_time.tv_usec);
|
||||
|
||||
if ( (!initialized)
|
||||
|| (diff >= 0.02) ) {
|
||||
std::string update = Terminal::Display::new_frame( initialized, state, new_frame );
|
||||
swrite( STDOUT_FILENO, update.c_str() );
|
||||
state = new_frame;
|
||||
|
||||
initialized = true;
|
||||
last_time = this_time;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* This is the main loop.
|
||||
|
||||
1. New bytes from the user get applied to the terminal emulator
|
||||
as "UserByte" actions.
|
||||
|
||||
2. New bytes from the host get sent to the Parser, and then
|
||||
those actions are applied to the terminal.
|
||||
|
||||
3. Resize events (from a SIGWINCH signal) get turned into
|
||||
"Resize" actions and applied to the terminal.
|
||||
|
||||
At every event from poll(), we run the tick() function to
|
||||
possibly print a new frame (if we haven't printed one in the
|
||||
last 1/50 second). The new frames are "differential" -- they
|
||||
assume the previous frame was sent to the real terminal.
|
||||
*/
|
||||
|
||||
void emulate_terminal( int fd )
|
||||
{
|
||||
/* 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 current window size */
|
||||
struct winsize window_size;
|
||||
if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 ) {
|
||||
perror( "ioctl TIOCGWINSZ" );
|
||||
return;
|
||||
}
|
||||
|
||||
/* tell child process */
|
||||
if ( ioctl( fd, TIOCSWINSZ, &window_size ) < 0 ) {
|
||||
perror( "ioctl TIOCSWINSZ" );
|
||||
return;
|
||||
}
|
||||
|
||||
/* open parser and terminal */
|
||||
Terminal::Complete complete( window_size.ws_col, window_size.ws_row );
|
||||
Terminal::Framebuffer state( window_size.ws_col, window_size.ws_row );
|
||||
|
||||
struct pollfd pollfds[ 3 ];
|
||||
|
||||
pollfds[ 0 ].fd = STDIN_FILENO;
|
||||
pollfds[ 0 ].events = POLLIN;
|
||||
|
||||
pollfds[ 1 ].fd = fd;
|
||||
pollfds[ 1 ].events = POLLIN;
|
||||
|
||||
pollfds[ 2 ].fd = winch_fd;
|
||||
pollfds[ 2 ].events = POLLIN;
|
||||
|
||||
swrite( STDOUT_FILENO, Terminal::Emulator::open().c_str() );
|
||||
|
||||
int poll_timeout = -1;
|
||||
|
||||
while ( 1 ) {
|
||||
int active_fds = poll( pollfds, 3, poll_timeout );
|
||||
if ( active_fds < 0 ) {
|
||||
perror( "poll" );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( pollfds[ 0 ].revents & POLLIN ) {
|
||||
/* input from user */
|
||||
char buf[ buf_size ];
|
||||
|
||||
/* fill buffer if possible */
|
||||
ssize_t bytes_read = read( pollfds[ 0 ].fd, buf, buf_size );
|
||||
if ( bytes_read == 0 ) { /* EOF */
|
||||
return;
|
||||
} else if ( bytes_read < 0 ) {
|
||||
perror( "read" );
|
||||
return;
|
||||
}
|
||||
|
||||
std::string terminal_to_host;
|
||||
|
||||
for ( int i = 0; i < bytes_read; i++ ) {
|
||||
Parser::UserByte ub( buf[ i ] );
|
||||
terminal_to_host += complete.act( &ub );
|
||||
}
|
||||
|
||||
if ( swrite( fd, terminal_to_host.c_str(), terminal_to_host.length() ) < 0 ) {
|
||||
break;
|
||||
}
|
||||
} else if ( pollfds[ 1 ].revents & POLLIN ) {
|
||||
/* input from host */
|
||||
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;
|
||||
}
|
||||
|
||||
std::string terminal_to_host = complete.act( std::string( buf, bytes_read ) );
|
||||
if ( swrite( fd, terminal_to_host.c_str(), terminal_to_host.length() ) < 0 ) {
|
||||
break;
|
||||
}
|
||||
} else if ( pollfds[ 2 ].revents & POLLIN ) {
|
||||
/* resize */
|
||||
struct signalfd_siginfo info;
|
||||
assert( read( winch_fd, &info, sizeof( info ) ) == sizeof( info ) );
|
||||
assert( info.ssi_signo == SIGWINCH );
|
||||
|
||||
/* get new size */
|
||||
if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 ) {
|
||||
perror( "ioctl TIOCGWINSZ" );
|
||||
return;
|
||||
}
|
||||
|
||||
/* tell emulator */
|
||||
Parser::Resize r( window_size.ws_col, window_size.ws_row );
|
||||
complete.act( &r );
|
||||
|
||||
/* tell child process */
|
||||
if ( ioctl( fd, TIOCSWINSZ, &window_size ) < 0 ) {
|
||||
perror( "ioctl TIOCSWINSZ" );
|
||||
return;
|
||||
}
|
||||
} else if ( (pollfds[ 0 ].revents | pollfds[ 1 ].revents)
|
||||
& (POLLERR | POLLHUP | POLLNVAL) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( tick( state, complete.get_fb()) ) { /* there was a frame */
|
||||
poll_timeout = -1;
|
||||
} else {
|
||||
poll_timeout = 20;
|
||||
}
|
||||
}
|
||||
|
||||
std::string update = Terminal::Display::new_frame( true, state, complete.get_fb() );
|
||||
swrite( STDOUT_FILENO, update.c_str() );
|
||||
|
||||
swrite( STDOUT_FILENO, Terminal::Emulator::close().c_str() );
|
||||
}
|
||||
Reference in New Issue
Block a user