clang-format Mosh

Run clang-format over the Mosh source tree. This is a large change and
has been factored into its own commit for auditability. Reproduce it
with

    find . -name \*.cc -or -name \*.h | while read f; do clang-format -i --style=file $f; done
This commit is contained in:
Benjamin Barenblat
2023-08-07 21:53:48 -04:00
committed by Alex Chernyakhovsky
parent 0b15dc94fa
commit 3acaa1c4d3
77 changed files with 4838 additions and 4848 deletions
+24 -28
View File
@@ -32,14 +32,14 @@ extern "C" {
/* Return status codes: Negative return values indicate an error occurred.
* For full explanations of error values, consult the implementation's
* documentation. */
#define AE_SUCCESS ( 0) /* Indicates successful completion of call */
#define AE_INVALID (-1) /* Indicates bad tag during decryption */
#define AE_NOT_SUPPORTED (-2) /* Indicates unsupported option requested */
#define AE_SUCCESS ( 0 ) /* Indicates successful completion of call */
#define AE_INVALID ( -1 ) /* Indicates bad tag during decryption */
#define AE_NOT_SUPPORTED ( -2 ) /* Indicates unsupported option requested */
/* Flags: When data can be processed "incrementally", these flags are used
* to indicate whether the submitted data is the last or not. */
#define AE_FINALIZE (1) /* This is the last of data */
#define AE_PENDING (0) /* More data of is coming */
#define AE_FINALIZE ( 1 ) /* This is the last of data */
#define AE_PENDING ( 0 ) /* More data of is coming */
/* --------------------------------------------------------------------------
*
@@ -55,10 +55,10 @@ typedef struct _ae_ctx ae_ctx;
*
* ----------------------------------------------------------------------- */
ae_ctx* ae_allocate (void *misc); /* Allocate ae_ctx, set optional ptr */
void ae_free (ae_ctx *ctx); /* Deallocate ae_ctx struct */
int ae_clear (ae_ctx *ctx); /* Undo initialization */
int ae_ctx_sizeof(void); /* Return sizeof(ae_ctx) */
ae_ctx* ae_allocate( void* misc ); /* Allocate ae_ctx, set optional ptr */
void ae_free( ae_ctx* ctx ); /* Deallocate ae_ctx struct */
int ae_clear( ae_ctx* ctx ); /* Undo initialization */
int ae_ctx_sizeof( void ); /* Return sizeof(ae_ctx) */
/* ae_allocate() allocates an ae_ctx structure, but does not initialize it.
* ae_free() deallocates an ae_ctx structure, but does not zeroize it.
* ae_clear() zeroes sensitive values associated with an ae_ctx structure
@@ -72,11 +72,7 @@ int ae_ctx_sizeof(void); /* Return sizeof(ae_ctx) */
*
* ----------------------------------------------------------------------- */
int ae_init(ae_ctx *ctx,
const void *key,
int key_len,
int nonce_len,
int tag_len);
int ae_init( ae_ctx* ctx, const void* key, int key_len, int nonce_len, int tag_len );
/* --------------------------------------------------------------------------
*
* Initialize an ae_ctx context structure.
@@ -95,15 +91,15 @@ int ae_init(ae_ctx *ctx,
*
* ----------------------------------------------------------------------- */
int ae_encrypt(ae_ctx *ctx,
const void *nonce,
const void *pt,
int ae_encrypt( ae_ctx* ctx,
const void* nonce,
const void* pt,
int pt_len,
const void *ad,
const void* ad,
int ad_len,
void *ct,
void *tag,
int final);
void* ct,
void* tag,
int final );
/* --------------------------------------------------------------------------
*
* Encrypt plaintext; provide for authentication of ciphertext/associated data.
@@ -132,15 +128,15 @@ int ae_encrypt(ae_ctx *ctx,
*
* ----------------------------------------------------------------------- */
int ae_decrypt(ae_ctx *ctx,
const void *nonce,
const void *ct,
int ae_decrypt( ae_ctx* ctx,
const void* nonce,
const void* ct,
int ct_len,
const void *ad,
const void* ad,
int ad_len,
void *pt,
const void *tag,
int final);
void* pt,
const void* tag,
int final );
/* --------------------------------------------------------------------------
*
* Decrypt ciphertext; provide authenticity of plaintext and associated data.
+17 -19
View File
@@ -33,8 +33,8 @@
#include <cstdlib>
#include <cstring>
#include "src/util/fatal_assert.h"
#include "src/crypto/base64.h"
#include "src/util/fatal_assert.h"
static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -60,27 +60,26 @@ static const unsigned char reverse[] = {
};
/* Reverse maps from an ASCII char to a base64 sixbit value. Returns > 0x3f on failure. */
static unsigned char base64_char_to_sixbit(unsigned char c)
static unsigned char base64_char_to_sixbit( unsigned char c )
{
return reverse[c];
}
bool base64_decode( const char *b64, const size_t b64_len,
uint8_t *raw, size_t *raw_len )
bool base64_decode( const char* b64, const size_t b64_len, uint8_t* raw, size_t* raw_len )
{
fatal_assert( b64_len == 24 ); /* only useful for Mosh keys */
fatal_assert( *raw_len == 16 );
uint32_t bytes = 0;
for (int i = 0; i < 22; i++) {
unsigned char sixbit = base64_char_to_sixbit(*(b64++));
if (sixbit > 0x3f) {
for ( int i = 0; i < 22; i++ ) {
unsigned char sixbit = base64_char_to_sixbit( *( b64++ ) );
if ( sixbit > 0x3f ) {
return false;
}
bytes <<= 6;
bytes |= sixbit;
/* write groups of 3 */
if (i % 4 == 3) {
if ( i % 4 == 3 ) {
raw[0] = bytes >> 16;
raw[1] = bytes >> 8;
raw[2] = bytes;
@@ -90,33 +89,32 @@ bool base64_decode( const char *b64, const size_t b64_len,
}
/* last byte of output */
*raw = bytes >> 4;
if (b64[0] != '=' || b64[1] != '=') {
if ( b64[0] != '=' || b64[1] != '=' ) {
return false;
}
return true;
}
void base64_encode( const uint8_t *raw, const size_t raw_len,
char *b64, const size_t b64_len )
void base64_encode( const uint8_t* raw, const size_t raw_len, char* b64, const size_t b64_len )
{
fatal_assert( b64_len == 24 ); /* only useful for Mosh keys */
fatal_assert( raw_len == 16 );
/* first 15 bytes of input */
for (int i = 0; i < 5; i++) {
uint32_t bytes = (raw[0] << 16) | (raw[1] << 8) | raw[2];
b64[0] = table[(bytes >> 18) & 0x3f];
b64[1] = table[(bytes >> 12) & 0x3f];
b64[2] = table[(bytes >> 6) & 0x3f];
b64[3] = table[(bytes) & 0x3f];
for ( int i = 0; i < 5; i++ ) {
uint32_t bytes = ( raw[0] << 16 ) | ( raw[1] << 8 ) | raw[2];
b64[0] = table[( bytes >> 18 ) & 0x3f];
b64[1] = table[( bytes >> 12 ) & 0x3f];
b64[2] = table[( bytes >> 6 ) & 0x3f];
b64[3] = table[(bytes)&0x3f];
raw += 3;
b64 += 4;
}
/* last byte of input, last 4 of output */
uint8_t lastchar = *raw;
b64[0] = table[(lastchar >> 2) & 0x3f];
b64[1] = table[(lastchar << 4) & 0x3f];
b64[0] = table[( lastchar >> 2 ) & 0x3f];
b64[1] = table[( lastchar << 4 ) & 0x3f];
b64[2] = '=';
b64[3] = '=';
}
+2 -4
View File
@@ -32,8 +32,6 @@
#include <cstdint>
bool base64_decode( const char *b64, const size_t b64_len,
uint8_t *raw, size_t *raw_len );
bool base64_decode( const char* b64, const size_t b64_len, uint8_t* raw, size_t* raw_len );
void base64_encode( const uint8_t *raw, const size_t raw_len,
char *b64, const size_t b64_len );
void base64_encode( const uint8_t* raw, const size_t raw_len, char* b64, const size_t b64_len );
+34 -39
View File
@@ -37,12 +37,12 @@
#if HAVE_DECL_BE64TOH || HAVE_DECL_BETOH64
# if defined(HAVE_ENDIAN_H)
# include <endian.h>
# elif defined(HAVE_SYS_ENDIAN_H)
# include <sys/types.h>
# include <sys/endian.h>
# endif
#if defined( HAVE_ENDIAN_H )
#include <endian.h>
#elif defined( HAVE_SYS_ENDIAN_H )
#include <sys/endian.h>
#include <sys/types.h>
#endif
#if !HAVE_DECL_BE64TOH && HAVE_DECL_BETOH64
#define be64toh betoh64
@@ -50,11 +50,11 @@
#endif
#elif HAVE_OSX_SWAP
# include <libkern/OSByteOrder.h>
# define htobe64 OSSwapHostToBigInt64
# define be64toh OSSwapBigToHostInt64
# define htobe16 OSSwapHostToBigInt16
# define be16toh OSSwapBigToHostInt16
#include <libkern/OSByteOrder.h>
#define htobe64 OSSwapHostToBigInt64
#define be64toh OSSwapBigToHostInt64
#define htobe16 OSSwapHostToBigInt16
#define be16toh OSSwapBigToHostInt16
#else
@@ -70,60 +70,55 @@
/* Use unions rather than casts, to comply with strict aliasing rules. */
inline uint64_t htobe64( uint64_t x ) {
uint8_t xs[ 8 ] = {
static_cast<uint8_t>( ( x >> 56 ) & 0xFF ),
inline uint64_t htobe64( uint64_t x )
{
uint8_t xs[8] = { static_cast<uint8_t>( ( x >> 56 ) & 0xFF ),
static_cast<uint8_t>( ( x >> 48 ) & 0xFF ),
static_cast<uint8_t>( ( x >> 40 ) & 0xFF ),
static_cast<uint8_t>( ( x >> 32 ) & 0xFF ),
static_cast<uint8_t>( ( x >> 24 ) & 0xFF ),
static_cast<uint8_t>( ( x >> 16 ) & 0xFF ),
static_cast<uint8_t>( ( x >> 8 ) & 0xFF ),
static_cast<uint8_t>( ( x ) & 0xFF ) };
static_cast<uint8_t>( (x)&0xFF ) };
union {
const uint8_t *p8;
const uint64_t *p64;
const uint8_t* p8;
const uint64_t* p64;
} u;
u.p8 = xs;
return *u.p64;
}
inline uint64_t be64toh( uint64_t x ) {
inline uint64_t be64toh( uint64_t x )
{
union {
const uint8_t *p8;
const uint64_t *p64;
const uint8_t* p8;
const uint64_t* p64;
} u;
u.p64 = &x;
return ( uint64_t( u.p8[ 0 ] ) << 56 )
| ( uint64_t( u.p8[ 1 ] ) << 48 )
| ( uint64_t( u.p8[ 2 ] ) << 40 )
| ( uint64_t( u.p8[ 3 ] ) << 32 )
| ( uint64_t( u.p8[ 4 ] ) << 24 )
| ( uint64_t( u.p8[ 5 ] ) << 16 )
| ( uint64_t( u.p8[ 6 ] ) << 8 )
| ( uint64_t( u.p8[ 7 ] ) );
return ( uint64_t( u.p8[0] ) << 56 ) | ( uint64_t( u.p8[1] ) << 48 ) | ( uint64_t( u.p8[2] ) << 40 )
| ( uint64_t( u.p8[3] ) << 32 ) | ( uint64_t( u.p8[4] ) << 24 ) | ( uint64_t( u.p8[5] ) << 16 )
| ( uint64_t( u.p8[6] ) << 8 ) | ( uint64_t( u.p8[7] ) );
}
inline uint16_t htobe16( uint16_t x ) {
uint8_t xs[ 2 ] = {
static_cast<uint8_t>( ( x >> 8 ) & 0xFF ),
static_cast<uint8_t>( ( x ) & 0xFF ) };
inline uint16_t htobe16( uint16_t x )
{
uint8_t xs[2] = { static_cast<uint8_t>( ( x >> 8 ) & 0xFF ), static_cast<uint8_t>( (x)&0xFF ) };
union {
const uint8_t *p8;
const uint16_t *p16;
const uint8_t* p8;
const uint16_t* p16;
} u;
u.p8 = xs;
return *u.p16;
}
inline uint16_t be16toh( uint16_t x ) {
inline uint16_t be16toh( uint16_t x )
{
union {
const uint8_t *p8;
const uint16_t *p16;
const uint8_t* p8;
const uint16_t* p16;
} u;
u.p16 = &x;
return ( uint16_t( u.p8[ 0 ] ) << 8 )
| ( uint16_t( u.p8[ 1 ] ) );
return ( uint16_t( u.p8[0] ) << 8 ) | ( uint16_t( u.p8[1] ) );
}
#endif
+30 -33
View File
@@ -39,23 +39,22 @@
#include <sys/resource.h>
#include "src/crypto/base64.h"
#include "src/crypto/byteorder.h"
#include "src/crypto/crypto.h"
#include "src/crypto/base64.h"
#include "src/util/fatal_assert.h"
#include "src/crypto/prng.h"
#include "src/util/fatal_assert.h"
using namespace Crypto;
long int myatoi( const char *str )
long int myatoi( const char* str )
{
char *end;
char* end;
errno = 0;
long int ret = strtol( str, &end, 10 );
if ( ( errno != 0 )
|| ( end != str + strlen( str ) ) ) {
if ( ( errno != 0 ) || ( end != str + strlen( str ) ) ) {
throw CryptoException( "Bad integer." );
}
@@ -72,16 +71,14 @@ uint64_t Crypto::unique( void )
return rv;
}
AlignedBuffer::AlignedBuffer( size_t len, const char *data )
: m_len( len ), m_allocated( NULL ), m_data( NULL )
AlignedBuffer::AlignedBuffer( size_t len, const char* data ) : m_len( len ), m_allocated( NULL ), m_data( NULL )
{
size_t alloc_len = len ? len : 1;
#if defined(HAVE_POSIX_MEMALIGN)
if ( ( 0 != posix_memalign( &m_allocated, 16, alloc_len ) )
|| ( m_allocated == NULL ) ) {
#if defined( HAVE_POSIX_MEMALIGN )
if ( ( 0 != posix_memalign( &m_allocated, 16, alloc_len ) ) || ( m_allocated == NULL ) ) {
throw std::bad_alloc();
}
m_data = (char *) m_allocated;
m_data = (char*)m_allocated;
#else
/* malloc() a region 15 bytes larger than we need, and find
@@ -91,15 +88,15 @@ AlignedBuffer::AlignedBuffer( size_t len, const char *data )
throw std::bad_alloc();
}
uintptr_t iptr = (uintptr_t) m_allocated;
uintptr_t iptr = (uintptr_t)m_allocated;
if ( iptr & 0xF ) {
iptr += 16 - ( iptr & 0xF );
}
assert( !( iptr & 0xF ) );
assert( iptr >= (uintptr_t) m_allocated );
assert( iptr <= ( 15 + (uintptr_t) m_allocated ) );
assert( iptr >= (uintptr_t)m_allocated );
assert( iptr <= ( 15 + (uintptr_t)m_allocated ) );
m_data = (char *) iptr;
m_data = (char*)iptr;
#endif /* !defined(HAVE_POSIX_MEMALIGN) */
@@ -136,32 +133,28 @@ Base64Key::Base64Key()
PRNG().fill( key, sizeof( key ) );
}
Base64Key::Base64Key(PRNG &prng)
Base64Key::Base64Key( PRNG& prng )
{
prng.fill( key, sizeof( key ) );
}
std::string Base64Key::printable_key( void ) const
{
char base64[ 24 ];
char base64[24];
base64_encode( key, 16, base64, 24 );
if ( (base64[ 23 ] != '=')
|| (base64[ 22 ] != '=') ) {
if ( ( base64[23] != '=' ) || ( base64[22] != '=' ) ) {
throw CryptoException( std::string( "Unexpected output from base64_encode: " ) + std::string( base64, 24 ) );
}
base64[ 22 ] = 0;
base64[22] = 0;
return std::string( base64 );
}
Session::Session( Base64Key s_key )
: key( s_key ), ctx_buf( ae_ctx_sizeof() ),
ctx( (ae_ctx *)ctx_buf.data() ), blocks_encrypted( 0 ),
plaintext_buffer( RECEIVE_MTU ),
ciphertext_buffer( RECEIVE_MTU ),
nonce_buffer( Nonce::NONCE_LEN )
: key( s_key ), ctx_buf( ae_ctx_sizeof() ), ctx( (ae_ctx*)ctx_buf.data() ), blocks_encrypted( 0 ),
plaintext_buffer( RECEIVE_MTU ), ciphertext_buffer( RECEIVE_MTU ), nonce_buffer( Nonce::NONCE_LEN )
{
if ( AE_SUCCESS != ae_init( ctx, key.data(), 16, 12, 16 ) ) {
throw CryptoException( "Could not initialize AES-OCB context." );
@@ -188,7 +181,7 @@ uint64_t Nonce::val( void ) const
return be64toh( ret );
}
Nonce::Nonce( const char *s_bytes, size_t len )
Nonce::Nonce( const char* s_bytes, size_t len )
{
if ( len != 8 ) {
throw CryptoException( "Nonce representation must be 8 octets long." );
@@ -198,7 +191,7 @@ Nonce::Nonce( const char *s_bytes, size_t len )
memcpy( bytes + 4, s_bytes, 8 );
}
const std::string Session::encrypt( const Message & plaintext )
const std::string Session::encrypt( const Message& plaintext )
{
const size_t pt_len = plaintext.text.size();
const int ciphertext_len = pt_len + 16;
@@ -209,7 +202,8 @@ const std::string Session::encrypt( const Message & plaintext )
memcpy( plaintext_buffer.data(), plaintext.text.data(), pt_len );
memcpy( nonce_buffer.data(), plaintext.nonce.data(), Nonce::NONCE_LEN );
if ( ciphertext_len != ae_encrypt( ctx, /* ctx */
if ( ciphertext_len
!= ae_encrypt( ctx, /* ctx */
nonce_buffer.data(), /* nonce */
plaintext_buffer.data(), /* pt */
pt_len, /* pt_len */
@@ -248,7 +242,7 @@ const std::string Session::encrypt( const Message & plaintext )
return plaintext.nonce.cc_str() + text;
}
const Message Session::decrypt( const char *str, size_t len )
const Message Session::decrypt( const char* str, size_t len )
{
if ( len < 24 ) {
throw CryptoException( "Ciphertext must contain nonce and tag." );
@@ -269,7 +263,8 @@ const Message Session::decrypt( const char *str, size_t len )
memcpy( ciphertext_buffer.data(), str + 8, body_len );
memcpy( nonce_buffer.data(), nonce.data(), Nonce::NONCE_LEN );
if ( pt_len != ae_decrypt( ctx, /* ctx */
if ( pt_len
!= ae_decrypt( ctx, /* ctx */
nonce_buffer.data(), /* nonce */
ciphertext_buffer.data(), /* ct */
body_len, /* ct_len */
@@ -290,7 +285,8 @@ static rlim_t saved_core_rlimit;
/* Disable dumping core, as a precaution to avoid saving sensitive data
to disk. */
void Crypto::disable_dumping_core( void ) {
void Crypto::disable_dumping_core( void )
{
struct rlimit limit;
if ( 0 != getrlimit( RLIMIT_CORE, &limit ) ) {
/* We don't throw CryptoException because this is called very early
@@ -307,7 +303,8 @@ void Crypto::disable_dumping_core( void ) {
}
}
void Crypto::reenable_dumping_core( void ) {
void Crypto::reenable_dumping_core( void )
{
/* Silent failure is safe. */
struct rlimit limit;
if ( 0 == getrlimit( RLIMIT_CORE, &limit ) ) {
+62 -65
View File
@@ -41,107 +41,106 @@
#include <exception>
#include <string>
long int myatoi( const char *str );
long int myatoi( const char* str );
class PRNG;
namespace Crypto {
class CryptoException : public std::exception {
public:
class CryptoException : public std::exception
{
public:
std::string text;
bool fatal;
CryptoException( std::string s_text, bool s_fatal = false )
: text( s_text ), fatal( s_fatal ) {};
const char *what() const throw () { return text.c_str(); }
~CryptoException() throw () {}
};
CryptoException( std::string s_text, bool s_fatal = false ) : text( s_text ), fatal( s_fatal ) {};
const char* what() const throw() { return text.c_str(); }
~CryptoException() throw() {}
};
/*
/*
* OCB (and other algorithms) require a source of nonce/sequence
* numbers that never repeats its output. Enforce that with this
* function.
*/
uint64_t unique( void );
uint64_t unique( void );
/* 16-byte-aligned buffer, with length. */
class AlignedBuffer {
private:
/* 16-byte-aligned buffer, with length. */
class AlignedBuffer
{
private:
size_t m_len;
void *m_allocated;
char *m_data;
void* m_allocated;
char* m_data;
public:
AlignedBuffer( size_t len, const char *data = NULL );
public:
AlignedBuffer( size_t len, const char* data = NULL );
~AlignedBuffer() {
free( m_allocated );
}
~AlignedBuffer() { free( m_allocated ); }
char * data( void ) const { return m_data; }
char* data( void ) const { return m_data; }
size_t len( void ) const { return m_len; }
private:
private:
/* Not implemented */
AlignedBuffer( const AlignedBuffer & );
AlignedBuffer & operator=( const AlignedBuffer & );
};
AlignedBuffer( const AlignedBuffer& );
AlignedBuffer& operator=( const AlignedBuffer& );
};
class Base64Key {
private:
unsigned char key[ 16 ];
class Base64Key
{
private:
unsigned char key[16];
public:
public:
Base64Key(); /* random key */
Base64Key(PRNG &prng);
Base64Key( PRNG& prng );
Base64Key( std::string printable_key );
std::string printable_key( void ) const;
unsigned char *data( void ) { return key; }
};
unsigned char* data( void ) { return key; }
};
class Nonce {
public:
class Nonce
{
public:
static const int NONCE_LEN = 12;
private:
char bytes[ NONCE_LEN ];
private:
char bytes[NONCE_LEN];
public:
public:
Nonce( uint64_t val );
Nonce( const char *s_bytes, size_t len );
Nonce( const char* s_bytes, size_t len );
std::string cc_str( void ) const { return std::string( bytes + 4, 8 ); }
const char *data( void ) const { return bytes; }
const char* data( void ) const { return bytes; }
uint64_t val( void ) const;
};
};
class Message {
public:
class Message
{
public:
const Nonce nonce;
const std::string text;
Message( const char *nonce_bytes, size_t nonce_len,
const char *text_bytes, size_t text_len )
: nonce( nonce_bytes, nonce_len ),
text( text_bytes, text_len ) {}
Message( const char* nonce_bytes, size_t nonce_len, const char* text_bytes, size_t text_len )
: nonce( nonce_bytes, nonce_len ), text( text_bytes, text_len )
{}
Message( const Nonce & s_nonce, const std::string & s_text )
: nonce( s_nonce ),
text( s_text ) {}
};
Message( const Nonce& s_nonce, const std::string& s_text ) : nonce( s_nonce ), text( s_text ) {}
};
class Session {
private:
class Session
{
private:
Base64Key key;
AlignedBuffer ctx_buf;
ae_ctx *ctx;
ae_ctx* ctx;
uint64_t blocks_encrypted;
AlignedBuffer plaintext_buffer;
AlignedBuffer ciphertext_buffer;
AlignedBuffer nonce_buffer;
public:
public:
static const int RECEIVE_MTU = 2048;
/* Overhead (not counting the nonce, which is handled by network transport) */
static const int ADDED_BYTES = 16 /* final OCB block */;
@@ -149,18 +148,16 @@ namespace Crypto {
Session( Base64Key s_key );
~Session();
const std::string encrypt( const Message & plaintext );
const Message decrypt( const char *str, size_t len );
const Message decrypt( const std::string & ciphertext ) {
return decrypt( ciphertext.data(), ciphertext.size() );
}
const std::string encrypt( const Message& plaintext );
const Message decrypt( const char* str, size_t len );
const Message decrypt( const std::string& ciphertext ) { return decrypt( ciphertext.data(), ciphertext.size() ); }
Session( const Session & );
Session & operator=( const Session & );
};
Session( const Session& );
Session& operator=( const Session& );
};
void disable_dumping_core( void );
void reenable_dumping_core( void );
void disable_dumping_core( void );
void reenable_dumping_core( void );
}
#endif
+97 -76
View File
@@ -1,188 +1,209 @@
#include "src/include/config.h"
#include "src/crypto/ae.h"
#include "src/include/config.h"
#include <cstring>
#include <openssl/crypto.h>
#include <openssl/evp.h>
struct _ae_ctx {
EVP_CIPHER_CTX *enc_ctx;
EVP_CIPHER_CTX *dec_ctx;
struct _ae_ctx
{
EVP_CIPHER_CTX* enc_ctx;
EVP_CIPHER_CTX* dec_ctx;
int tag_len;
};
int ae_clear(ae_ctx* ctx) {
EVP_CIPHER_CTX_free(ctx->enc_ctx);
EVP_CIPHER_CTX_free(ctx->dec_ctx);
OPENSSL_cleanse(ctx, sizeof(*ctx));
int ae_clear( ae_ctx* ctx )
{
EVP_CIPHER_CTX_free( ctx->enc_ctx );
EVP_CIPHER_CTX_free( ctx->dec_ctx );
OPENSSL_cleanse( ctx, sizeof( *ctx ) );
return AE_SUCCESS;
}
int ae_ctx_sizeof() {
return sizeof(_ae_ctx);
int ae_ctx_sizeof()
{
return sizeof( _ae_ctx );
}
// If direction is 1, initializes encryption. If 0, initializes
// decryption. See the documentation of EVP_CipherInit_ex
static int ae_evp_cipher_init(EVP_CIPHER_CTX **in_ctx, int direction,
const unsigned char *key,
int nonce_len, int tag_len) {
static int ae_evp_cipher_init( EVP_CIPHER_CTX** in_ctx,
int direction,
const unsigned char* key,
int nonce_len,
int tag_len )
{
// Create an OpenSSL EVP context. It does not yet have any specific
// cipher associated with it.
if (!(*in_ctx = EVP_CIPHER_CTX_new())) {
if ( !( *in_ctx = EVP_CIPHER_CTX_new() ) ) {
return -3;
}
EVP_CIPHER_CTX *ctx = *in_ctx;
EVP_CIPHER_CTX* ctx = *in_ctx;
// Although OCB-AES has the same initialization process between
// encryption and decryption, an EVP_CIPHER_CTX must be initialized
// for a specific direction.
if (EVP_CipherInit_ex(ctx, EVP_aes_128_ocb(),
/*impl=*/NULL, /*key=*/key, /*iv=*/NULL,
direction) != 1) {
if ( EVP_CipherInit_ex( ctx,
EVP_aes_128_ocb(),
/*impl=*/NULL,
/*key=*/key,
/*iv=*/NULL,
direction )
!= 1 ) {
return -3;
}
// Attempt to set the nonce length. If it fails, the length must not
// be supported. However, that should have been handled by the
// pre-condition check above.
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN,
nonce_len, NULL) != 1) {
if ( EVP_CIPHER_CTX_ctrl( ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce_len, NULL ) != 1 ) {
return -3;
}
// A NULL tag length means that EVP_CTRL_AEAD_SET_TAG is only being
// used to set the length
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
tag_len, NULL) != 1) {
if ( EVP_CIPHER_CTX_ctrl( ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL ) != 1 ) {
return -3;
}
return AE_SUCCESS;
}
int ae_init(ae_ctx *ctx, const void *key, int key_len, int nonce_len,
int tag_len) {
int ae_init( ae_ctx* ctx, const void* key, int key_len, int nonce_len, int tag_len )
{
// Pre-condition: Only nonces of length 12 are supported. The
// documentation of `ae_init` in ae.h specifies that `ctx` is
// untouched if an invalid configuration is requested. Delegating
// this to OpenSSL would happen too late; `ctx` has already been
// modified.
if (nonce_len != 12) {
if ( nonce_len != 12 ) {
return AE_NOT_SUPPORTED;
}
// Pre-condition: Only AES-128 is supported.
if (key_len != 16) {
if ( key_len != 16 ) {
return AE_NOT_SUPPORTED;
}
int r = AE_SUCCESS;
if ((r = ae_evp_cipher_init(&ctx->enc_ctx, 1,
reinterpret_cast<const unsigned char *>(key),
nonce_len, tag_len))!= AE_SUCCESS) {
if ( ( r = ae_evp_cipher_init(
&ctx->enc_ctx, 1, reinterpret_cast<const unsigned char*>( key ), nonce_len, tag_len ) )
!= AE_SUCCESS ) {
return r;
}
if ((r = ae_evp_cipher_init(&ctx->dec_ctx, 0,
reinterpret_cast<const unsigned char *>(key),
nonce_len, tag_len)) != AE_SUCCESS) {
if ( ( r = ae_evp_cipher_init(
&ctx->dec_ctx, 0, reinterpret_cast<const unsigned char*>( key ), nonce_len, tag_len ) )
!= AE_SUCCESS ) {
return r;
}
ctx->tag_len = tag_len;
return AE_SUCCESS;
}
int ae_encrypt(ae_ctx *ctx, const void *nonce_ptr, const void *pt_ptr,
int pt_len, const void *ad_ptr, int ad_len, void *ct_ptr,
void *tag, int final) {
const unsigned char *nonce =
reinterpret_cast<const unsigned char *>(nonce_ptr);
const unsigned char *pt = reinterpret_cast<const unsigned char *>(pt_ptr);
const unsigned char* ad = reinterpret_cast<const unsigned char *>(ad_ptr);
unsigned char* ct = reinterpret_cast<unsigned char *>(ct_ptr);
int ae_encrypt( ae_ctx* ctx,
const void* nonce_ptr,
const void* pt_ptr,
int pt_len,
const void* ad_ptr,
int ad_len,
void* ct_ptr,
void* tag,
int final )
{
const unsigned char* nonce = reinterpret_cast<const unsigned char*>( nonce_ptr );
const unsigned char* pt = reinterpret_cast<const unsigned char*>( pt_ptr );
const unsigned char* ad = reinterpret_cast<const unsigned char*>( ad_ptr );
unsigned char* ct = reinterpret_cast<unsigned char*>( ct_ptr );
// Streaming mode is not supported; nonce must always be provided.
if (final != AE_FINALIZE) {
if ( final != AE_FINALIZE ) {
return AE_NOT_SUPPORTED;
}
if (nonce == NULL) {
if ( nonce == NULL ) {
return AE_NOT_SUPPORTED;
}
if (EVP_EncryptInit_ex(ctx->enc_ctx, /*type=*/NULL, /*impl=*/NULL,
/*key=*/NULL, nonce) != 1) {
if ( EVP_EncryptInit_ex( ctx->enc_ctx,
/*type=*/NULL,
/*impl=*/NULL,
/*key=*/NULL,
nonce )
!= 1 ) {
return -3;
}
int len = 0;
if (ad != NULL && ad_len > 0 &&
EVP_EncryptUpdate(ctx->enc_ctx, /*out=*/NULL, &len, ad, ad_len) != 1) {
if ( ad != NULL && ad_len > 0 && EVP_EncryptUpdate( ctx->enc_ctx, /*out=*/NULL, &len, ad, ad_len ) != 1 ) {
return -3;
}
len = 0;
if (pt != NULL && pt_len > 0 &&
EVP_EncryptUpdate(ctx->enc_ctx, ct, &len, pt, pt_len) != 1) {
if ( pt != NULL && pt_len > 0 && EVP_EncryptUpdate( ctx->enc_ctx, ct, &len, pt, pt_len ) != 1 ) {
return -3;
}
int ciphertext_len = len;
if (EVP_EncryptFinal_ex(ctx->enc_ctx, ct + ciphertext_len, &len) != 1) {
if ( EVP_EncryptFinal_ex( ctx->enc_ctx, ct + ciphertext_len, &len ) != 1 ) {
return -3;
}
ciphertext_len += len;
// If `tag` is provided, the authentication tag goes
// there. Otherwise, it is appended after the ciphertext.
void *tag_location = tag != NULL ? tag : ct + ciphertext_len;
if (EVP_CIPHER_CTX_ctrl(ctx->enc_ctx, EVP_CTRL_AEAD_GET_TAG,
ctx->tag_len, tag_location) != 1) {
void* tag_location = tag != NULL ? tag : ct + ciphertext_len;
if ( EVP_CIPHER_CTX_ctrl( ctx->enc_ctx, EVP_CTRL_AEAD_GET_TAG, ctx->tag_len, tag_location ) != 1 ) {
return -3;
}
if (tag == NULL) {
if ( tag == NULL ) {
ciphertext_len += ctx->tag_len;
}
return ciphertext_len;
}
int ae_decrypt(ae_ctx *ctx, const void *nonce_ptr, const void *ct_ptr,
int ct_len, const void *ad_ptr, int ad_len, void *pt_ptr,
const void *tag, int final) {
const unsigned char *nonce =
reinterpret_cast<const unsigned char *>(nonce_ptr);
const unsigned char *ct = reinterpret_cast<const unsigned char *>(ct_ptr);
const unsigned char* ad = reinterpret_cast<const unsigned char *>(ad_ptr);
unsigned char* pt = reinterpret_cast<unsigned char *>(pt_ptr);
if (ct_len < ctx->tag_len) {
int ae_decrypt( ae_ctx* ctx,
const void* nonce_ptr,
const void* ct_ptr,
int ct_len,
const void* ad_ptr,
int ad_len,
void* pt_ptr,
const void* tag,
int final )
{
const unsigned char* nonce = reinterpret_cast<const unsigned char*>( nonce_ptr );
const unsigned char* ct = reinterpret_cast<const unsigned char*>( ct_ptr );
const unsigned char* ad = reinterpret_cast<const unsigned char*>( ad_ptr );
unsigned char* pt = reinterpret_cast<unsigned char*>( pt_ptr );
if ( ct_len < ctx->tag_len ) {
return AE_INVALID;
}
// If an external tag is not provided, then the tag is assumed to be
// the final bytes of the cipher text. Subtract it off now so the
// plaintext does not accidentally try to decrypt the AEAD tag (and
// then cause an authentication failure).
if (tag == NULL) {
if ( tag == NULL ) {
ct_len -= ctx->tag_len;
}
// Like encryption, nonce must always be provided and streaming is not supported.
if (final != AE_FINALIZE) {
if ( final != AE_FINALIZE ) {
return AE_NOT_SUPPORTED;
}
if (nonce == NULL) {
if ( nonce == NULL ) {
return AE_NOT_SUPPORTED;
}
if (EVP_DecryptInit_ex(ctx->dec_ctx, /*type=*/NULL, /*impl=*/NULL,
/*key=*/NULL, nonce) != 1) {
if ( EVP_DecryptInit_ex( ctx->dec_ctx,
/*type=*/NULL,
/*impl=*/NULL,
/*key=*/NULL,
nonce )
!= 1 ) {
return -3;
}
int len = 0;
if (ad != NULL && ad_len > 0 &&
EVP_DecryptUpdate(ctx->dec_ctx, /*out=*/NULL, &len, ad, ad_len) != 1) {
if ( ad != NULL && ad_len > 0 && EVP_DecryptUpdate( ctx->dec_ctx, /*out=*/NULL, &len, ad, ad_len ) != 1 ) {
return -3;
}
len = 0;
if (ct != NULL && ct_len > 0 &&
EVP_DecryptUpdate(ctx->dec_ctx, pt, &len, ct, ct_len) != 1) {
if ( ct != NULL && ct_len > 0 && EVP_DecryptUpdate( ctx->dec_ctx, pt, &len, ct, ct_len ) != 1 ) {
return -3;
}
int plaintext_len = len;
// If `tag` is provided, the authentication is read from
// there. Otherwise, it's the last bytes of the ciphertext. (This is
// a convention, not a requirement of OCB mode).
const void *tag_location = tag != NULL ? tag : ct + ct_len;
if (EVP_CIPHER_CTX_ctrl(ctx->dec_ctx, EVP_CTRL_AEAD_SET_TAG,
ctx->tag_len, (void *)tag_location) != 1) {
const void* tag_location = tag != NULL ? tag : ct + ct_len;
if ( EVP_CIPHER_CTX_ctrl( ctx->dec_ctx, EVP_CTRL_AEAD_SET_TAG, ctx->tag_len, (void*)tag_location ) != 1 ) {
return -3;
}
if (EVP_DecryptFinal_ex(ctx->dec_ctx, pt + plaintext_len, &len) != 1) {
if ( EVP_DecryptFinal_ex( ctx->dec_ctx, pt + plaintext_len, &len ) != 1 ) {
return AE_INVALID;
}
plaintext_len += len;
+15 -10
View File
@@ -47,41 +47,46 @@ static const char rdev[] = "/dev/urandom";
using namespace Crypto;
class PRNG {
private:
class PRNG
{
private:
std::ifstream randfile;
/* unimplemented to satisfy -Weffc++ */
PRNG( const PRNG & );
PRNG & operator=( const PRNG & );
PRNG( const PRNG& );
PRNG& operator=( const PRNG& );
public:
public:
PRNG() : randfile( rdev, std::ifstream::in | std::ifstream::binary ) {}
void fill( void *dest, size_t size ) {
void fill( void* dest, size_t size )
{
if ( 0 == size ) {
return;
}
randfile.read( static_cast<char *>( dest ), size );
randfile.read( static_cast<char*>( dest ), size );
if ( !randfile ) {
throw CryptoException( "Could not read from " + std::string( rdev ) );
}
}
uint8_t uint8() {
uint8_t uint8()
{
uint8_t x;
fill( &x, 1 );
return x;
}
uint32_t uint32() {
uint32_t uint32()
{
uint32_t x;
fill( &x, 4 );
return x;
}
uint64_t uint64() {
uint64_t uint64()
{
uint64_t x;
fill( &x, 8 );
return x;
+22 -24
View File
@@ -53,41 +53,41 @@
#include <util.h>
#endif
#include "src/util/swrite.h"
#include "src/frontend/terminaloverlay.h"
#include "src/statesync/completeterminal.h"
#include "src/statesync/user.h"
#include "src/frontend/terminaloverlay.h"
#include "src/util/locale_utils.h"
#include "src/util/fatal_assert.h"
#include "src/util/locale_utils.h"
#include "src/util/swrite.h"
const int ITERATIONS = 100000;
using namespace Terminal;
int main( int argc, char **argv )
int main( int argc, char** argv )
{
try {
int fbmod = 0;
int width = 80, height = 24;
int iterations = ITERATIONS;
if (argc > 1) {
iterations = atoi(argv[1]);
if (iterations < 1 || iterations > 1000000000) {
fprintf(stderr, "bogus iteration count\n");
exit(1);
if ( argc > 1 ) {
iterations = atoi( argv[1] );
if ( iterations < 1 || iterations > 1000000000 ) {
fprintf( stderr, "bogus iteration count\n" );
exit( 1 );
}
}
if (argc > 3) {
width = atoi(argv[2]);
height = atoi(argv[3]);
if (width < 1 || width > 1000 || height < 1 || height > 1000) {
fprintf(stderr, "bogus window size\n");
exit(1);
if ( argc > 3 ) {
width = atoi( argv[2] );
height = atoi( argv[3] );
if ( width < 1 || width > 1000 || height < 1 || height > 1000 ) {
fprintf( stderr, "bogus window size\n" );
exit( 1 );
}
}
Framebuffer local_framebuffers[ 2 ] = { Framebuffer(width,height), Framebuffer(width,height) };
Framebuffer *local_framebuffer = &(local_framebuffers[ fbmod ]);
Framebuffer *new_state = &(local_framebuffers[ !fbmod ]);
Framebuffer local_framebuffers[2] = { Framebuffer( width, height ), Framebuffer( width, height ) };
Framebuffer* local_framebuffer = &( local_framebuffers[fbmod] );
Framebuffer* new_state = &( local_framebuffers[!fbmod] );
Overlay::OverlayManager overlays;
Display display( true );
Complete local_terminal( width, height );
@@ -107,9 +107,7 @@ int main( int argc, char **argv )
overlays.apply( *new_state );
/* calculate minimal difference from where we are */
const std::string diff( display.new_frame( false,
*local_framebuffer,
*new_state ) );
const std::string diff( display.new_frame( false, *local_framebuffer, *new_state ) );
/* make sure to use diff */
if ( diff.size() > INT_MAX ) {
@@ -117,10 +115,10 @@ int main( int argc, char **argv )
}
fbmod = !fbmod;
local_framebuffer = &(local_framebuffers[ fbmod ]);
new_state = &(local_framebuffers[ !fbmod ]);
local_framebuffer = &( local_framebuffers[fbmod] );
new_state = &( local_framebuffers[!fbmod] );
}
} catch ( const std::exception &e ) {
} catch ( const std::exception& e ) {
fprintf( stderr, "Exception caught: %s\n", e.what() );
return 1;
}
+5 -6
View File
@@ -38,15 +38,15 @@
using namespace Crypto;
int main( int argc, char *argv[] )
int main( int argc, char* argv[] )
{
if ( argc != 2 ) {
fprintf( stderr, "Usage: %s KEY\n", argv[ 0 ] );
fprintf( stderr, "Usage: %s KEY\n", argv[0] );
return 1;
}
try {
Base64Key key( argv[ 1 ] );
Base64Key key( argv[1] );
Session session( key );
/* Read input */
@@ -57,10 +57,9 @@ int main( int argc, char *argv[] )
Message message = session.decrypt( input.str() );
fprintf( stderr, "Nonce = %ld\n",
(long)message.nonce.val() );
fprintf( stderr, "Nonce = %ld\n", (long)message.nonce.val() );
std::cout << message.text;
} catch ( const CryptoException &e ) {
} catch ( const CryptoException& e ) {
std::cerr << e.what() << std::endl;
exit( 1 );
}
+4 -4
View File
@@ -38,17 +38,17 @@
using namespace Crypto;
int main( int argc, char *argv[] )
int main( int argc, char* argv[] )
{
if ( argc != 2 ) {
fprintf( stderr, "Usage: %s NONCE\n", argv[ 0 ] );
fprintf( stderr, "Usage: %s NONCE\n", argv[0] );
return 1;
}
try {
Base64Key key;
Session session( key );
Nonce nonce( myatoi( argv[ 1 ] ) );
Nonce nonce( myatoi( argv[1] ) );
/* Read input */
std::ostringstream input;
@@ -61,7 +61,7 @@ int main( int argc, char *argv[] )
std::cerr << "Key: " << key.printable_key() << std::endl;
std::cout << ciphertext;
} catch ( const CryptoException &e ) {
} catch ( const CryptoException& e ) {
std::cerr << e.what() << std::endl;
exit( 1 );
}
+21 -24
View File
@@ -35,38 +35,38 @@
#include <termios.h>
#include <unistd.h>
#include "src/network/networktransport-impl.h"
#include "src/statesync/user.h"
#include "src/util/fatal_assert.h"
#include "src/util/pty_compat.h"
#include "src/network/networktransport-impl.h"
#include "src/util/select.h"
using namespace Network;
int main( int argc, char *argv[] )
int main( int argc, char* argv[] )
{
bool server = true;
char *key;
char *ip;
char *port;
char* key;
char* ip;
char* port;
UserStream me, remote;
using NetworkPointer = std::shared_ptr<Transport<UserStream, UserStream>>;
Transport<UserStream, UserStream> *raw_n;
Transport<UserStream, UserStream>* raw_n;
try {
if ( argc > 1 ) {
server = false;
/* client */
key = argv[ 1 ];
ip = argv[ 2 ];
port = argv[ 3 ];
key = argv[1];
ip = argv[2];
port = argv[3];
raw_n = new Transport<UserStream, UserStream>( me, remote, key, ip, port );
} else {
raw_n = new Transport<UserStream, UserStream>( me, remote, NULL, NULL );
}
} catch ( const std::exception &e ) {
} catch ( const std::exception& e ) {
fprintf( stderr, "Fatal startup error: %s\n", e.what() );
exit( 1 );
}
@@ -74,12 +74,12 @@ int main( int argc, char *argv[] )
fprintf( stderr, "Port bound is %s, key is %s\n", n->port().c_str(), n->get_key().c_str() );
if ( server ) {
Select &sel = Select::get_instance();
Select& sel = Select::get_instance();
uint64_t last_num = n->get_remote_state_num();
while ( true ) {
try {
sel.clear_fds();
std::vector< int > fd_list( n->fds() );
std::vector<int> fd_list( n->fds() );
assert( fd_list.size() == 1 ); /* servers don't hop */
int network_fd = fd_list.back();
sel.add_fd( network_fd );
@@ -94,11 +94,12 @@ int main( int argc, char *argv[] )
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() );
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 ( const std::exception &e ) {
} catch ( const std::exception& e ) {
fprintf( stderr, "Server error: %s\n", e.what() );
}
}
@@ -120,16 +121,14 @@ int main( int argc, char *argv[] )
exit( 1 );
}
Select &sel = Select::get_instance();
Select& sel = Select::get_instance();
while( true ) {
while ( true ) {
sel.clear_fds();
sel.add_fd( STDIN_FILENO );
std::vector< int > fd_list( n->fds() );
for ( std::vector< int >::const_iterator it = fd_list.begin();
it != fd_list.end();
it++ ) {
std::vector<int> fd_list( n->fds() );
for ( std::vector<int>::const_iterator it = fd_list.begin(); it != fd_list.end(); it++ ) {
sel.add_fd( *it );
}
@@ -147,9 +146,7 @@ int main( int argc, char *argv[] )
}
bool network_ready_to_read = false;
for ( std::vector< int >::const_iterator it = fd_list.begin();
it != fd_list.end();
it++ ) {
for ( std::vector<int>::const_iterator it = fd_list.begin(); it != fd_list.end(); it++ ) {
if ( sel.read( *it ) ) {
/* packet received from the network */
/* we only read one socket each run */
@@ -160,7 +157,7 @@ int main( int argc, char *argv[] )
if ( network_ready_to_read ) {
n->recv();
}
} catch ( const std::exception &e ) {
} catch ( const std::exception& e ) {
fprintf( stderr, "Client error: %s\n", e.what() );
}
}
+19 -21
View File
@@ -55,21 +55,19 @@
#endif
#include "src/terminal/parser.h"
#include "src/util/swrite.h"
#include "src/util/locale_utils.h"
#include "src/util/fatal_assert.h"
#include "src/util/locale_utils.h"
#include "src/util/pty_compat.h"
#include "src/util/select.h"
#include "src/util/swrite.h"
const size_t buf_size = 1024;
static void emulate_terminal( int fd );
static int copy( int src, int dest );
static int vt_parser( int fd, Parser::UTF8Parser *parser );
static int vt_parser( int fd, Parser::UTF8Parser* parser );
int main( int argc __attribute__((unused)),
char *argv[] __attribute__((unused)),
char *envp[] )
int main( int argc __attribute__( ( unused ) ), char* argv[] __attribute__( ( unused ) ), char* envp[] )
{
int master;
struct termios saved_termios, raw_termios, child_termios;
@@ -85,12 +83,14 @@ int main( int argc __attribute__((unused)),
child_termios = saved_termios;
#ifdef HAVE_IUTF8
if ( !(child_termios.c_iflag & IUTF8) ) {
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;
}
#else
fprintf( stderr, "Warning: termios IUTF8 flag not defined. Character-erase of multibyte character sequence probably does not work properly on this platform.\n" );
fprintf( stderr,
"Warning: termios IUTF8 flag not defined. Character-erase of multibyte character sequence probably does "
"not work properly on this platform.\n" );
#endif /* HAVE_IUTF8 */
pid_t child = forkpty( &master, NULL, &child_termios, NULL );
@@ -102,11 +102,11 @@ int main( int argc __attribute__((unused)),
if ( child == 0 ) {
/* child */
char *my_argv[ 2 ];
my_argv[ 0 ] = strdup( "/bin/bash" );
assert( my_argv[ 0 ] );
char* my_argv[2];
my_argv[0] = strdup( "/bin/bash" );
assert( my_argv[0] );
my_argv[ 1 ] = NULL;
my_argv[1] = NULL;
if ( execve( "/bin/bash", my_argv, envp ) < 0 ) {
perror( "execve" );
@@ -139,7 +139,7 @@ static void emulate_terminal( int fd )
{
Parser::UTF8Parser parser;
Select &sel = Select::get_instance();
Select& sel = Select::get_instance();
sel.add_fd( STDIN_FILENO );
sel.add_fd( fd );
@@ -166,7 +166,7 @@ static void emulate_terminal( int fd )
static int copy( int src, int dest )
{
char buf[ buf_size ];
char buf[buf_size];
ssize_t bytes_read = read( src, buf, buf_size );
if ( bytes_read == 0 ) { /* EOF */
@@ -179,9 +179,9 @@ static int copy( int src, int dest )
return swrite( dest, buf, bytes_read );
}
static int vt_parser( int fd, Parser::UTF8Parser *parser )
static int vt_parser( int fd, Parser::UTF8Parser* parser )
{
char buf[ buf_size ];
char buf[buf_size];
/* fill buffer if possible */
ssize_t bytes_read = read( fd, buf, buf_size );
@@ -195,13 +195,11 @@ static int vt_parser( int fd, Parser::UTF8Parser *parser )
/* feed to parser */
Parser::Actions actions;
for ( int i = 0; i < bytes_read; i++ ) {
parser->input( buf[ i ], actions );
for ( Parser::Actions::iterator j = actions.begin();
j != actions.end();
j++ ) {
parser->input( buf[i], actions );
for ( Parser::Actions::iterator j = actions.begin(); j != actions.end(); j++ ) {
assert( *j );
Parser::Action &act = **j;
Parser::Action& act = **j;
if ( act.char_present ) {
if ( iswprint( act.ch ) ) {
+24 -25
View File
@@ -61,19 +61,19 @@
#include <libutil.h>
#endif
#include "src/terminal/parser.h"
#include "src/statesync/completeterminal.h"
#include "src/util/swrite.h"
#include "src/terminal/parser.h"
#include "src/util/fatal_assert.h"
#include "src/util/pty_compat.h"
#include "src/util/locale_utils.h"
#include "src/util/pty_compat.h"
#include "src/util/select.h"
#include "src/util/swrite.h"
const size_t buf_size = 16384;
static void emulate_terminal( int fd );
int main( int argc, char *argv[] )
int main( int argc, char* argv[] )
{
int master;
struct termios saved_termios, raw_termios, child_termios;
@@ -89,12 +89,14 @@ int main( int argc, char *argv[] )
child_termios = saved_termios;
#ifdef HAVE_IUTF8
if ( !(child_termios.c_iflag & IUTF8) ) {
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;
}
#else
fprintf( stderr, "Warning: termios IUTF8 flag not defined. Character-erase of multibyte character sequence probably does not work properly on this platform.\n" );
fprintf( stderr,
"Warning: termios IUTF8 flag not defined. Character-erase of multibyte character sequence probably does "
"not work properly on this platform.\n" );
#endif /* HAVE_IUTF8 */
pid_t child = forkpty( &master, NULL, &child_termios, NULL );
@@ -117,26 +119,26 @@ int main( int argc, char *argv[] )
exit( 1 );
}
char *my_argv[ 2 ];
char* my_argv[2];
if ( argc > 1 ) {
argv++;
} else {
/* get shell name */
my_argv[ 0 ] = getenv( "SHELL" );
if ( my_argv[ 0 ] == NULL || *my_argv[ 0 ] == '\0' ) {
struct passwd *pw = getpwuid( getuid() );
my_argv[0] = getenv( "SHELL" );
if ( my_argv[0] == NULL || *my_argv[0] == '\0' ) {
struct passwd* pw = getpwuid( getuid() );
if ( pw == NULL ) {
perror( "getpwuid" );
exit( 1 );
}
my_argv[ 0 ] = strdup( pw->pw_shell );
my_argv[0] = strdup( pw->pw_shell );
}
assert( my_argv[ 0 ] );
my_argv[ 1 ] = NULL;
assert( my_argv[0] );
my_argv[1] = NULL;
argv = my_argv;
}
if ( execvp( argv[ 0 ], argv ) < 0 ) {
if ( execvp( argv[0], argv ) < 0 ) {
perror( "execve" );
exit( 1 );
}
@@ -154,7 +156,7 @@ int main( int argc, char *argv[] )
try {
emulate_terminal( master );
} catch ( const std::exception &e ) {
} catch ( const std::exception& e ) {
fprintf( stderr, "\r\nException caught: %s\r\n", e.what() );
}
@@ -170,8 +172,7 @@ int main( int argc, char *argv[] )
}
/* Print a frame if the last frame was more than 1/50 seconds ago */
static bool tick( Terminal::Framebuffer &state, Terminal::Framebuffer &new_frame,
const Terminal::Display &display )
static bool tick( Terminal::Framebuffer& state, Terminal::Framebuffer& new_frame, const Terminal::Display& display )
{
static bool initialized = false;
static struct timeval last_time;
@@ -182,11 +183,9 @@ static bool tick( Terminal::Framebuffer &state, Terminal::Framebuffer &new_frame
perror( "gettimeofday" );
}
double diff = (this_time.tv_sec - last_time.tv_sec)
+ .000001 * (this_time.tv_usec - last_time.tv_usec);
double diff = ( this_time.tv_sec - last_time.tv_sec ) + .000001 * ( this_time.tv_usec - last_time.tv_usec );
if ( (!initialized)
|| (diff >= 0.02) ) {
if ( ( !initialized ) || ( diff >= 0.02 ) ) {
std::string update = display.new_frame( initialized, state, new_frame );
swrite( STDOUT_FILENO, update.c_str() );
state = new_frame;
@@ -239,7 +238,7 @@ static void emulate_terminal( int fd )
/* open display */
Terminal::Display display( true ); /* use TERM to initialize */
Select &sel = Select::get_instance();
Select& sel = Select::get_instance();
sel.add_fd( STDIN_FILENO );
sel.add_fd( fd );
sel.add_signal( SIGWINCH );
@@ -257,7 +256,7 @@ static void emulate_terminal( int fd )
if ( sel.read( STDIN_FILENO ) ) {
/* input from user */
char buf[ buf_size ];
char buf[buf_size];
/* fill buffer if possible */
ssize_t bytes_read = read( STDIN_FILENO, buf, buf_size );
@@ -271,7 +270,7 @@ static void emulate_terminal( int fd )
std::string terminal_to_host;
for ( int i = 0; i < bytes_read; i++ ) {
terminal_to_host += complete.act( Parser::UserByte( buf[ i ] ) );
terminal_to_host += complete.act( Parser::UserByte( buf[i] ) );
}
if ( swrite( fd, terminal_to_host.c_str(), terminal_to_host.length() ) < 0 ) {
@@ -279,7 +278,7 @@ static void emulate_terminal( int fd )
}
} else if ( sel.read( fd ) ) {
/* input from host */
char buf[ buf_size ];
char buf[buf_size];
/* fill buffer if possible */
ssize_t bytes_read = read( fd, buf, buf_size );
+45 -45
View File
@@ -37,10 +37,10 @@
#include <unistd.h>
#include "stmclient.h"
#include "src/crypto/crypto.h"
#include "src/util/locale_utils.h"
#include "src/util/fatal_assert.h"
#include "src/util/locale_utils.h"
#include "stmclient.h"
/* These need to be included last because of conflicting defines. */
/*
@@ -53,59 +53,62 @@
#endif
#if defined HAVE_NCURSESW_CURSES_H
# include <ncursesw/curses.h>
# include <ncursesw/term.h>
#include <ncursesw/curses.h>
#include <ncursesw/term.h>
#elif defined HAVE_NCURSESW_H
# include <ncursesw.h>
# include <term.h>
#include <ncursesw.h>
#include <term.h>
#elif defined HAVE_NCURSES_CURSES_H
# include <ncurses/curses.h>
# include <ncurses/term.h>
#include <ncurses/curses.h>
#include <ncurses/term.h>
#elif defined HAVE_NCURSES_H
# include <ncurses.h>
# include <term.h>
#include <ncurses.h>
#include <term.h>
#elif defined HAVE_CURSES_H
# include <curses.h>
# include <term.h>
#include <curses.h>
#include <term.h>
#else
# error "SysV or X/Open-compatible Curses header file required"
#error "SysV or X/Open-compatible Curses header file required"
#endif
static void print_version( FILE *file )
static void print_version( FILE* file )
{
fputs( "mosh-client (" PACKAGE_STRING ") [build " BUILD_VERSION "]\n"
"Copyright 2012 Keith Winstein <mosh-devel@mit.edu>\n"
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n", file );
"There is NO WARRANTY, to the extent permitted by law.\n",
file );
}
static void print_usage( FILE *file, const char *argv0 )
static void print_usage( FILE* file, const char* argv0 )
{
print_version( file );
fprintf( file, "\nUsage: %s [-# 'ARGS'] IP PORT\n"
" %s -c\n", argv0, argv0 );
fprintf( file,
"\nUsage: %s [-# 'ARGS'] IP PORT\n"
" %s -c\n",
argv0,
argv0 );
}
static void print_colorcount( void )
{
/* check colors */
setupterm((char *)0, 1, (int *)0);
setupterm( (char*)0, 1, (int*)0 );
char colors_name[] = "colors";
int color_val = tigetnum( colors_name );
if ( color_val == -2 ) {
fprintf( stderr, "Invalid terminfo numeric capability: %s\n",
colors_name );
fprintf( stderr, "Invalid terminfo numeric capability: %s\n", colors_name );
}
printf( "%d\n", color_val );
}
#ifdef NACL
int mosh_main( int argc, char *argv[] )
int mosh_main( int argc, char* argv[] )
#else
int main( int argc, char *argv[] )
int main( int argc, char* argv[] )
#endif
{
unsigned int verbose = 0;
@@ -117,18 +120,18 @@ int main( int argc, char *argv[] )
/* Get arguments */
for ( int i = 1; i < argc; i++ ) {
if ( 0 == strcmp( argv[ i ], "--help" ) ) {
print_usage( stdout, argv[ 0 ] );
if ( 0 == strcmp( argv[i], "--help" ) ) {
print_usage( stdout, argv[0] );
exit( 0 );
}
if ( 0 == strcmp( argv[ i ], "--version" ) ) {
if ( 0 == strcmp( argv[i], "--version" ) ) {
print_version( stdout );
exit( 0 );
}
}
int opt;
while ( (opt = getopt( argc, argv, "#:cv" )) != -1 ) {
while ( ( opt = getopt( argc, argv, "#:cv" ) ) != -1 ) {
switch ( opt ) {
case '#':
// Ignore the original arguments to mosh wrapper
@@ -141,7 +144,7 @@ int main( int argc, char *argv[] )
verbose++;
break;
default:
print_usage( stderr, argv[ 0 ] );
print_usage( stderr, argv[0] );
exit( 1 );
break;
}
@@ -150,34 +153,33 @@ int main( int argc, char *argv[] )
char *ip, *desired_port;
if ( argc - optind != 2 ) {
print_usage( stderr, argv[ 0 ] );
print_usage( stderr, argv[0] );
exit( 1 );
}
ip = argv[ optind ];
desired_port = argv[ optind + 1 ];
ip = argv[optind];
desired_port = argv[optind + 1];
/* Sanity-check arguments */
if ( desired_port
&& ( strspn( desired_port, "0123456789" ) != strlen( desired_port ) ) ) {
fprintf( stderr, "%s: Bad UDP port (%s)\n\n", argv[ 0 ], desired_port );
print_usage( stderr, argv[ 0 ] );
if ( desired_port && ( strspn( desired_port, "0123456789" ) != strlen( desired_port ) ) ) {
fprintf( stderr, "%s: Bad UDP port (%s)\n\n", argv[0], desired_port );
print_usage( stderr, argv[0] );
exit( 1 );
}
/* Read key from environment */
char *env_key = getenv( "MOSH_KEY" );
char* env_key = getenv( "MOSH_KEY" );
if ( env_key == NULL ) {
fputs( "MOSH_KEY environment variable not found.\n", stderr );
exit( 1 );
}
/* Read prediction preference */
char *predict_mode = getenv( "MOSH_PREDICTION_DISPLAY" );
char* predict_mode = getenv( "MOSH_PREDICTION_DISPLAY" );
/* can be NULL */
/* Read prediction insertion preference */
char *predict_overwrite = getenv( "MOSH_PREDICTION_OVERWRITE" );
char* predict_overwrite = getenv( "MOSH_PREDICTION_OVERWRITE" );
/* can be NULL */
std::string key( env_key );
@@ -203,15 +205,13 @@ int main( int argc, char *argv[] )
}
client.shutdown();
} catch ( const Network::NetworkException &e ) {
fprintf( stderr, "Network exception: %s\r\n",
e.what() );
} catch ( const Network::NetworkException& e ) {
fprintf( stderr, "Network exception: %s\r\n", e.what() );
success = false;
} catch ( const Crypto::CryptoException &e ) {
fprintf( stderr, "Crypto exception: %s\r\n",
e.what() );
} catch ( const Crypto::CryptoException& e ) {
fprintf( stderr, "Crypto exception: %s\r\n", e.what() );
success = false;
} catch ( const std::exception &e ) {
} catch ( const std::exception& e ) {
fprintf( stderr, "Error: %s\r\n", e.what() );
success = false;
}
+178 -177
View File
@@ -81,14 +81,13 @@
#endif
#include "src/statesync/completeterminal.h"
#include "src/util/swrite.h"
#include "src/statesync/user.h"
#include "src/util/fatal_assert.h"
#include "src/util/locale_utils.h"
#include "src/util/pty_compat.h"
#include "src/util/select.h"
#include "src/util/swrite.h"
#include "src/util/timestamp.h"
#include "src/util/fatal_assert.h"
#ifndef _PATH_BSHELL
#define _PATH_BSHELL "/bin/sh"
@@ -100,34 +99,40 @@ using ServerConnection = Network::Transport<Terminal::Complete, Network::UserStr
static void serve( int host_fd,
int pipe_fd,
Terminal::Complete &terminal,
ServerConnection &network,
Terminal::Complete& terminal,
ServerConnection& network,
long network_timeout,
long network_signaled_timeout );
static int run_server( const char *desired_ip, const char *desired_port,
const std::string &command_path, char *command_argv[],
const int colors, unsigned int verbose, bool with_motd );
static int run_server( const char* desired_ip,
const char* desired_port,
const std::string& command_path,
char* command_argv[],
const int colors,
unsigned int verbose,
bool with_motd );
static void print_version( FILE *file )
static void print_version( FILE* file )
{
fputs( "mosh-server (" PACKAGE_STRING ") [build " BUILD_VERSION "]\n"
"Copyright 2012 Keith Winstein <mosh-devel@mit.edu>\n"
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n", file );
"There is NO WARRANTY, to the extent permitted by law.\n",
file );
}
static void print_usage( FILE *stream, const char *argv0 )
static void print_usage( FILE* stream, const char* argv0 )
{
fprintf( stream, "Usage: %s new [-s] [-v] [-i LOCALADDR] [-p PORT[:PORT2]] [-c COLORS] [-l NAME=VALUE] [-- COMMAND...]\n", argv0 );
fprintf( stream,
"Usage: %s new [-s] [-v] [-i LOCALADDR] [-p PORT[:PORT2]] [-c COLORS] [-l NAME=VALUE] [-- COMMAND...]\n",
argv0 );
}
static bool print_motd( const char *filename );
static bool print_motd( const char* filename );
static void chdir_homedir( void );
static bool motd_hushed( void );
static void warn_unattached( const std::string & ignore_entry );
static void warn_unattached( const std::string& ignore_entry );
/* Simple spinloop */
static void spin( void )
@@ -146,7 +151,7 @@ static void spin( void )
static std::string get_SSH_IP( void )
{
const char *SSH_CONNECTION = getenv( "SSH_CONNECTION" );
const char* SSH_CONNECTION = getenv( "SSH_CONNECTION" );
if ( !SSH_CONNECTION ) { /* Older sshds don't set this */
fputs( "Warning: SSH_CONNECTION not found; binding to any interface.\n", stderr );
return std::string( "" );
@@ -170,7 +175,7 @@ static std::string get_SSH_IP( void )
return local_interface_IP;
}
int main( int argc, char *argv[] )
int main( int argc, char* argv[] )
{
/* For security, make sure we don't dump core */
Crypto::disable_dumping_core();
@@ -178,11 +183,11 @@ int main( int argc, char *argv[] )
/* Detect edge case */
fatal_assert( argc > 0 );
const char *desired_ip = NULL;
const char* desired_ip = NULL;
std::string desired_ip_str;
const char *desired_port = NULL;
const char* desired_port = NULL;
std::string command_path;
char **command_argv = NULL;
char** command_argv = NULL;
int colors = 0;
unsigned int verbose = 0; /* don't close stdin/stdout/stderr */
/* Will cause mosh-server not to correctly detach on old versions of sshd. */
@@ -190,15 +195,15 @@ int main( int argc, char *argv[] )
/* strip off command */
for ( int i = 1; i < argc; i++ ) {
if ( 0 == strcmp( argv[ i ], "--help" ) || 0 == strcmp( argv[ i ], "-h" ) ) {
print_usage( stdout, argv[ 0 ] );
if ( 0 == strcmp( argv[i], "--help" ) || 0 == strcmp( argv[i], "-h" ) ) {
print_usage( stdout, argv[0] );
exit( 0 );
}
if ( 0 == strcmp( argv[ i ], "--version" ) ) {
if ( 0 == strcmp( argv[i], "--version" ) ) {
print_version( stdout );
exit( 0 );
}
if ( 0 == strcmp( argv[ i ], "--" ) ) { /* -- is mandatory */
if ( 0 == strcmp( argv[i], "--" ) ) { /* -- is mandatory */
if ( i != argc - 1 ) {
command_argv = argv + i + 1;
}
@@ -208,11 +213,10 @@ int main( int argc, char *argv[] )
}
/* Parse new command-line syntax */
if ( (argc >= 2)
&& (strcmp( argv[ 1 ], "new" ) == 0) ) {
if ( ( argc >= 2 ) && ( strcmp( argv[1], "new" ) == 0 ) ) {
/* new option syntax */
int opt;
while ( (opt = getopt( argc - 1, argv + 1, "@:i:p:c:svl:" )) != -1 ) {
while ( ( opt = getopt( argc - 1, argv + 1, "@:i:p:c:svl:" ) ) != -1 ) {
switch ( opt ) {
/*
* This undocumented option does nothing but eat its argument.
@@ -241,9 +245,9 @@ int main( int argc, char *argv[] )
case 'c':
try {
colors = myatoi( optarg );
} catch ( const CryptoException & ) {
fprintf( stderr, "%s: Bad number of colors (%s)\n", argv[ 0 ], optarg );
print_usage( stderr, argv[ 0 ] );
} catch ( const CryptoException& ) {
fprintf( stderr, "%s: Bad number of colors (%s)\n", argv[0], optarg );
print_usage( stderr, argv[0] );
exit( 1 );
}
break;
@@ -255,7 +259,7 @@ int main( int argc, char *argv[] )
break;
default:
/* don't die on unknown options */
print_usage( stderr, argv[ 0 ] );
print_usage( stderr, argv[0] );
break;
}
}
@@ -263,37 +267,37 @@ int main( int argc, char *argv[] )
/* legacy argument parsing for older client wrapper script */
/* do nothing */
} else if ( argc == 2 ) {
desired_ip = argv[ 1 ];
desired_ip = argv[1];
} else if ( argc == 3 ) {
desired_ip = argv[ 1 ];
desired_port = argv[ 2 ];
desired_ip = argv[1];
desired_port = argv[2];
} else {
print_usage( stderr, argv[ 0 ] );
print_usage( stderr, argv[0] );
exit( 1 );
}
/* Sanity-check arguments */
int dpl, dph;
if ( desired_port && ! Connection::parse_portrange( desired_port, dpl, dph ) ) {
fprintf( stderr, "%s: Bad UDP port range (%s)\n", argv[ 0 ], desired_port );
print_usage( stderr, argv[ 0 ] );
if ( desired_port && !Connection::parse_portrange( desired_port, dpl, dph ) ) {
fprintf( stderr, "%s: Bad UDP port range (%s)\n", argv[0], desired_port );
print_usage( stderr, argv[0] );
exit( 1 );
}
bool with_motd = false;
#ifdef HAVE_SYSLOG
openlog(argv[0], LOG_PID | LOG_NDELAY, LOG_AUTH);
#endif
#ifdef HAVE_SYSLOG
openlog( argv[0], LOG_PID | LOG_NDELAY, LOG_AUTH );
#endif
/* Get shell */
char *my_argv[ 2 ];
char* my_argv[2];
std::string shell_name;
if ( !command_argv ) {
/* get shell name */
const char *shell = getenv( "SHELL" );
const char* shell = getenv( "SHELL" );
if ( shell == NULL ) {
struct passwd *pw = getpwuid( getuid() );
struct passwd* pw = getpwuid( getuid() );
if ( pw == NULL ) {
perror( "getpwuid" );
exit( 1 );
@@ -308,18 +312,18 @@ int main( int argc, char *argv[] )
command_path = shell_path;
size_t shell_slash( shell_path.rfind('/') );
size_t shell_slash( shell_path.rfind( '/' ) );
if ( shell_slash == std::string::npos ) {
shell_name = shell_path;
} else {
shell_name = shell_path.substr(shell_slash + 1);
shell_name = shell_path.substr( shell_slash + 1 );
}
/* prepend '-' to make login shell */
shell_name = '-' + shell_name;
my_argv[ 0 ] = const_cast<char *>( shell_name.c_str() );
my_argv[ 1 ] = NULL;
my_argv[0] = const_cast<char*>( shell_name.c_str() );
my_argv[1] = NULL;
command_argv = my_argv;
with_motd = true;
@@ -338,10 +342,8 @@ int main( int argc, char *argv[] )
/* apply locale-related environment variables from client */
clear_locale_variables();
for ( std::list<std::string>::const_iterator i = locale_vars.begin();
i != locale_vars.end();
i++ ) {
char *env_string = strdup( i->c_str() );
for ( std::list<std::string>::const_iterator i = locale_vars.begin(); i != locale_vars.end(); i++ ) {
char* env_string = strdup( i->c_str() );
fatal_assert( env_string );
if ( 0 != putenv( env_string ) ) {
perror( "putenv" );
@@ -354,39 +356,46 @@ int main( int argc, char *argv[] )
LocaleVar client_ctype = get_ctype();
std::string client_charset( locale_charset() );
fprintf( stderr, "mosh-server needs a UTF-8 native locale to run.\n\n"
fprintf( stderr,
"mosh-server needs a UTF-8 native locale to run.\n\n"
"Unfortunately, the local environment (%s) specifies\n"
"the character set \"%s\",\n\n"
"The client-supplied environment (%s) specifies\n"
"the character set \"%s\".\n\n",
native_ctype.str().c_str(), native_charset.c_str(), client_ctype.str().c_str(), client_charset.c_str() );
int unused __attribute((unused)) = system( "locale" );
native_ctype.str().c_str(),
native_charset.c_str(),
client_ctype.str().c_str(),
client_charset.c_str() );
int unused __attribute( ( unused ) ) = system( "locale" );
exit( 1 );
}
}
try {
return run_server( desired_ip, desired_port, command_path, command_argv, colors, verbose, with_motd );
} catch ( const Network::NetworkException &e ) {
fprintf( stderr, "Network exception: %s\n",
e.what() );
} catch ( const Network::NetworkException& e ) {
fprintf( stderr, "Network exception: %s\n", e.what() );
return 1;
} catch ( const Crypto::CryptoException &e ) {
fprintf( stderr, "Crypto exception: %s\n",
e.what() );
} catch ( const Crypto::CryptoException& e ) {
fprintf( stderr, "Crypto exception: %s\n", e.what() );
return 1;
}
}
static int run_server( const char *desired_ip, const char *desired_port,
const std::string &command_path, char *command_argv[],
const int colors, unsigned int verbose, bool with_motd ) {
static int run_server( const char* desired_ip,
const char* desired_port,
const std::string& command_path,
char* command_argv[],
const int colors,
unsigned int verbose,
bool with_motd )
{
/* get network idle timeout */
long network_timeout = 0;
char *timeout_envar = getenv( "MOSH_SERVER_NETWORK_TMOUT" );
char* timeout_envar = getenv( "MOSH_SERVER_NETWORK_TMOUT" );
if ( timeout_envar && *timeout_envar ) {
errno = 0;
char *endptr;
char* endptr;
network_timeout = strtol( timeout_envar, &endptr, 10 );
if ( *endptr != '\0' || ( network_timeout == 0 && errno == EINVAL ) ) {
fputs( "MOSH_SERVER_NETWORK_TMOUT not a valid integer, ignoring\n", stderr );
@@ -397,10 +406,10 @@ static int run_server( const char *desired_ip, const char *desired_port,
}
/* get network signaled idle timeout */
long network_signaled_timeout = 0;
char *signal_envar = getenv( "MOSH_SERVER_SIGNAL_TMOUT" );
char* signal_envar = getenv( "MOSH_SERVER_SIGNAL_TMOUT" );
if ( signal_envar && *signal_envar ) {
errno = 0;
char *endptr;
char* endptr;
network_signaled_timeout = strtol( signal_envar, &endptr, 10 );
if ( *endptr != '\0' || ( network_signaled_timeout == 0 && errno == EINVAL ) ) {
fputs( "MOSH_SERVER_SIGNAL_TMOUT not a valid integer, ignoring\n", stderr );
@@ -411,9 +420,7 @@ static int run_server( const char *desired_ip, const char *desired_port,
}
/* get initial window size */
struct winsize window_size;
if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 ||
window_size.ws_col == 0 ||
window_size.ws_row == 0 ) {
if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 || window_size.ws_col == 0 || window_size.ws_row == 0 ) {
/* Fill in sensible defaults. */
/* They will be overwritten by client on first connection. */
memset( &window_size, 0, sizeof( window_size ) );
@@ -450,7 +457,6 @@ static int run_server( const char *desired_ip, const char *desired_port,
fatal_assert( 0 == sigaction( SIGHUP, &sa, NULL ) );
fatal_assert( 0 == sigaction( SIGPIPE, &sa, NULL ) );
/* detach from terminal */
fflush( NULL );
pid_t the_pid = fork();
@@ -461,13 +467,15 @@ static int run_server( const char *desired_ip, const char *desired_port,
"Copyright 2012 Keith Winstein <mosh-devel@mit.edu>\n"
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n\n", stderr );
"There is NO WARRANTY, to the extent permitted by law.\n\n",
stderr );
fprintf( stderr, "[mosh-server detached, pid = %d]\n", static_cast<int>(the_pid) );
fprintf( stderr, "[mosh-server detached, pid = %d]\n", static_cast<int>( the_pid ) );
#ifndef HAVE_IUTF8
fputs( "\nWarning: termios IUTF8 flag not defined.\n"
"Character-erase of multibyte character sequence\n"
"probably does not work properly on this platform.\n", stderr );
"probably does not work properly on this platform.\n",
stderr );
#endif /* HAVE_IUTF8 */
fflush( NULL );
@@ -493,9 +501,8 @@ static int run_server( const char *desired_ip, const char *desired_port,
exit( 1 );
}
if ( dup2 ( nullfd, STDIN_FILENO ) < 0 ||
dup2 ( nullfd, STDOUT_FILENO ) < 0 ||
dup2 ( nullfd, STDERR_FILENO ) < 0 ) {
if ( dup2( nullfd, STDIN_FILENO ) < 0 || dup2( nullfd, STDOUT_FILENO ) < 0
|| dup2( nullfd, STDERR_FILENO ) < 0 ) {
perror( "dup2" );
exit( 1 );
}
@@ -506,13 +513,13 @@ static int run_server( const char *desired_ip, const char *desired_port,
}
}
char utmp_entry[ 64 ] = { 0 };
char utmp_entry[64] = { 0 };
snprintf( utmp_entry, 64, "mosh [%ld]", static_cast<long int>( getpid() ) );
/* Fork child process */
int pipes[2];
int success = pipe(pipes);
if (success == -1) {
int success = pipe( pipes );
if ( success == -1 ) {
perror( "pipe" );
exit( 1 );
}
@@ -538,9 +545,9 @@ static int run_server( const char *desired_ip, const char *desired_port,
fatal_assert( 0 == sigaction( SIGHUP, &sa, NULL ) );
fatal_assert( 0 == sigaction( SIGPIPE, &sa, NULL ) );
#ifdef HAVE_SYSLOG
#ifdef HAVE_SYSLOG
closelog();
#endif
#endif
/* close server-related file descriptors */
network.reset();
@@ -565,7 +572,7 @@ static int run_server( const char *desired_ip, const char *desired_port,
const char default_term[] = "xterm";
const char color_term[] = "xterm-256color";
if ( setenv( "TERM", (colors == 256) ? color_term : default_term, true ) < 0 ) {
if ( setenv( "TERM", ( colors == 256 ) ? color_term : default_term, true ) < 0 ) {
perror( "setenv" );
exit( 1 );
}
@@ -584,7 +591,7 @@ static int run_server( const char *desired_ip, const char *desired_port,
chdir_homedir();
if ( with_motd && (!motd_hushed()) ) {
if ( with_motd && ( !motd_hushed() ) ) {
// On illumos motd is printed by /etc/profile.
#ifndef __sun
// For Ubuntu, try and print one of {,/var}/run/motd.dynamic.
@@ -593,11 +600,11 @@ static int run_server( const char *desired_ip, const char *desired_port,
// this always happens.
// XXX Hackish knowledge of Ubuntu PAM configuration.
// But this seems less awful than build-time detection with autoconf.
if (!print_motd("/run/motd.dynamic")) {
print_motd("/var/run/motd.dynamic");
if ( !print_motd( "/run/motd.dynamic" ) ) {
print_motd( "/var/run/motd.dynamic" );
}
// Always print traditional /etc/motd.
print_motd("/etc/motd");
print_motd( "/etc/motd" );
#endif
warn_unattached( utmp_entry );
}
@@ -626,7 +633,7 @@ static int run_server( const char *desired_ip, const char *desired_port,
}
} else {
/* parent */
if ( close(pipes[0]) < 0 ) {
if ( close( pipes[0] ) < 0 ) {
perror( "parent read pipe close" );
exit( 1 );
}
@@ -634,7 +641,7 @@ static int run_server( const char *desired_ip, const char *desired_port,
/* Drop unnecessary privileges */
#ifdef HAVE_PLEDGE
/* OpenBSD pledge() syscall */
if ( pledge( "stdio inet tty", NULL )) {
if ( pledge( "stdio inet tty", NULL ) ) {
perror( "pledge() failed" );
exit( 1 );
}
@@ -647,17 +654,15 @@ static int run_server( const char *desired_ip, const char *desired_port,
try {
serve( master, pipes[1], terminal, *network, network_timeout, network_signaled_timeout );
} catch ( const Network::NetworkException &e ) {
fprintf( stderr, "Network exception: %s\n",
e.what() );
} catch ( const Crypto::CryptoException &e ) {
fprintf( stderr, "Crypto exception: %s\n",
e.what() );
} catch ( const Network::NetworkException& e ) {
fprintf( stderr, "Network exception: %s\n", e.what() );
} catch ( const Crypto::CryptoException& e ) {
fprintf( stderr, "Crypto exception: %s\n", e.what() );
}
#ifdef HAVE_UTEMPTER
#ifdef HAVE_UTEMPTER
utempter_remove_record( master );
#endif
#endif
if ( close( master ) < 0 ) {
perror( "close" );
@@ -670,35 +675,40 @@ static int run_server( const char *desired_ip, const char *desired_port,
return 0;
}
static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, ServerConnection &network, long network_timeout, long network_signaled_timeout )
static void serve( int host_fd,
int pipe_fd,
Terminal::Complete& terminal,
ServerConnection& network,
long network_timeout,
long network_signaled_timeout )
{
/* scale timeouts */
const uint64_t network_timeout_ms = static_cast<uint64_t>( network_timeout ) * 1000;
const uint64_t network_signaled_timeout_ms = static_cast<uint64_t>( network_signaled_timeout ) * 1000;
/* prepare to poll for events */
Select &sel = Select::get_instance();
Select& sel = Select::get_instance();
sel.add_signal( SIGTERM );
sel.add_signal( SIGINT );
sel.add_signal( SIGUSR1 );
uint64_t last_remote_num = network.get_remote_state_num();
#ifdef HAVE_UTEMPTER
#ifdef HAVE_UTEMPTER
bool connected_utmp = false;
#endif
#if defined(HAVE_SYSLOG) || defined(HAVE_UTEMPTER)
#endif
#if defined( HAVE_SYSLOG ) || defined( HAVE_UTEMPTER )
bool force_connection_change_evt = false;
Addr saved_addr;
socklen_t saved_addr_len = 0;
#endif
#endif
#ifdef HAVE_SYSLOG
struct passwd *pw = getpwuid( getuid() );
if (pw == NULL) {
#ifdef HAVE_SYSLOG
struct passwd* pw = getpwuid( getuid() );
if ( pw == NULL ) {
throw NetworkException( std::string( "serve: getpwuid: " ) + strerror( errno ), 0 );
}
syslog(LOG_INFO, "user %s session begin", pw->pw_name);
#endif
syslog( LOG_INFO, "user %s session begin", pw->pw_name );
#endif
bool child_released = false;
@@ -710,8 +720,7 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve
timeout = std::min( timeout, network.wait_time() );
timeout = std::min( timeout, terminal.wait_time( now ) );
if ( (!network.get_remote_state_num())
|| network.shutdown_in_progress() ) {
if ( ( !network.get_remote_state_num() ) || network.shutdown_in_progress() ) {
timeout = std::min( timeout, 5000 );
}
/*
@@ -719,20 +728,19 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve
* We may want to wake up sooner.
*/
if ( network_timeout_ms ) {
int64_t network_sleep = network_timeout_ms -
( now - network.get_latest_remote_state().timestamp );
int64_t network_sleep = network_timeout_ms - ( now - network.get_latest_remote_state().timestamp );
if ( network_sleep < 0 ) {
network_sleep = 0;
} else if ( network_sleep > INT_MAX ) {
/* 24 days might be too soon. That's OK. */
network_sleep = INT_MAX;
}
timeout = std::min( timeout, static_cast<int>(network_sleep) );
timeout = std::min( timeout, static_cast<int>( network_sleep ) );
}
/* poll for events */
sel.clear_fds();
std::vector< int > fd_list( network.fds() );
std::vector<int> fd_list( network.fds() );
assert( fd_list.size() == 1 ); /* servers don't hop */
int network_fd = fd_list.back();
sel.add_fd( network_fd );
@@ -758,22 +766,21 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve
if ( network.get_remote_state_num() != last_remote_num ) {
last_remote_num = network.get_remote_state_num();
Network::UserStream us;
us.apply_string( network.get_remote_diff() );
/* apply userstream to terminal */
for ( size_t i = 0; i < us.size(); i++ ) {
const Parser::Action &action = us.get_action( i );
const Parser::Action& action = us.get_action( i );
if ( typeid( action ) == typeid( Parser::Resize ) ) {
/* apply only the last consecutive Resize action */
if ( i < us.size() - 1 ) {
const Parser::Action &next = us.get_action( i + 1 );
const Parser::Action& next = us.get_action( i + 1 );
if ( typeid( next ) == typeid( Parser::Resize ) ) {
continue;
}
}
/* tell child process of resize */
const Parser::Resize &res = static_cast<const Parser::Resize &>( action );
const Parser::Resize& res = static_cast<const Parser::Resize&>( action );
struct winsize window_size;
if ( ioctl( host_fd, TIOCGWINSZ, &window_size ) < 0 ) {
perror( "ioctl TIOCGWINSZ" );
@@ -798,51 +805,48 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve
if ( !network.shutdown_in_progress() ) {
network.set_current_state( terminal );
}
#if defined(HAVE_SYSLOG) || defined(HAVE_UTEMPTER)
#ifdef HAVE_UTEMPTER
if (!connected_utmp) {
#if defined( HAVE_SYSLOG ) || defined( HAVE_UTEMPTER )
#ifdef HAVE_UTEMPTER
if ( !connected_utmp ) {
force_connection_change_evt = true;
} else {
force_connection_change_evt = false;
}
#else
#else
force_connection_change_evt = false;
#endif
#endif
/**
* - HAVE_UTEMPTER - update utmp entry if we have become "connected"
* - HAVE_SYSLOG - log connection information to syslog
**/
if ( (force_connection_change_evt)
|| saved_addr_len != network.get_remote_addr_len()
|| memcmp( &saved_addr, &network.get_remote_addr(),
saved_addr_len ) != 0 ) {
if ( ( force_connection_change_evt ) || saved_addr_len != network.get_remote_addr_len()
|| memcmp( &saved_addr, &network.get_remote_addr(), saved_addr_len ) != 0 ) {
saved_addr = network.get_remote_addr();
saved_addr_len = network.get_remote_addr_len();
char host[ NI_MAXHOST ];
int errcode = getnameinfo( &saved_addr.sa, saved_addr_len,
host, sizeof( host ), NULL, 0,
NI_NUMERICHOST );
char host[NI_MAXHOST];
int errcode
= getnameinfo( &saved_addr.sa, saved_addr_len, host, sizeof( host ), NULL, 0, NI_NUMERICHOST );
if ( errcode != 0 ) {
throw NetworkException( std::string( "serve: getnameinfo: " ) + gai_strerror( errcode ), 0 );
}
#ifdef HAVE_UTEMPTER
#ifdef HAVE_UTEMPTER
utempter_remove_record( host_fd );
char tmp[ 64 + NI_MAXHOST ];
char tmp[64 + NI_MAXHOST];
snprintf( tmp, 64 + NI_MAXHOST, "%s via mosh [%ld]", host, static_cast<long int>( getpid() ) );
utempter_add_record( host_fd, tmp );
connected_utmp = true;
#endif
#endif
#ifdef HAVE_SYSLOG
syslog(LOG_INFO, "user %s connected from host: %s", pw->pw_name, host);
#endif
#ifdef HAVE_SYSLOG
syslog( LOG_INFO, "user %s connected from host: %s", pw->pw_name, host );
#endif
}
#endif
#endif
/* Tell child to start login session. */
if ( !child_released ) {
@@ -854,10 +858,10 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve
}
}
if ( (!network.shutdown_in_progress()) && sel.read( host_fd ) ) {
if ( ( !network.shutdown_in_progress() ) && sel.read( host_fd ) ) {
/* input from the host needs to be fed to the terminal */
const int buf_size = 16384;
char buf[ buf_size ];
char buf[buf_size];
/* fill buffer if possible */
ssize_t bytes_read = read( host_fd, buf, buf_size );
@@ -880,22 +884,23 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve
}
bool idle_shutdown = false;
if ( network_timeout_ms &&
network_timeout_ms <= time_since_remote_state ) {
if ( network_timeout_ms && network_timeout_ms <= time_since_remote_state ) {
idle_shutdown = true;
fprintf( stderr, "Network idle for %llu seconds.\n",
fprintf( stderr,
"Network idle for %llu seconds.\n",
static_cast<unsigned long long>( time_since_remote_state / 1000 ) );
}
if ( sel.signal( SIGUSR1 )
&& ( !network_signaled_timeout_ms || network_signaled_timeout_ms <= time_since_remote_state ) ) {
idle_shutdown = true;
fprintf( stderr, "Network idle for %llu seconds when SIGUSR1 received\n",
fprintf( stderr,
"Network idle for %llu seconds when SIGUSR1 received\n",
static_cast<unsigned long long>( time_since_remote_state / 1000 ) );
}
if ( sel.any_signal() || idle_shutdown ) {
/* shutdown signal */
if ( network.has_remote_addr() && (!network.shutdown_in_progress()) ) {
if ( network.has_remote_addr() && ( !network.shutdown_in_progress() ) ) {
network.start_shutdown();
} else {
break;
@@ -917,37 +922,36 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve
break;
}
#ifdef HAVE_UTEMPTER
#ifdef HAVE_UTEMPTER
/* update utmp if has been more than 30 seconds since heard from client */
if ( connected_utmp
&& time_since_remote_state > 30000 ) {
if ( connected_utmp && time_since_remote_state > 30000 ) {
utempter_remove_record( host_fd );
char tmp[ 64 ];
char tmp[64];
snprintf( tmp, 64, "mosh [%ld]", static_cast<long int>( getpid() ) );
utempter_add_record( host_fd, tmp );
connected_utmp = false;
}
#endif
#endif
if ( terminal.set_echo_ack( now ) && !network.shutdown_in_progress() ) {
/* update client with new echo ack */
network.set_current_state( terminal );
}
if ( !network.get_remote_state_num()
&& time_since_remote_state >= timeout_if_no_client ) {
fprintf( stderr, "No connection within %llu seconds.\n",
if ( !network.get_remote_state_num() && time_since_remote_state >= timeout_if_no_client ) {
fprintf( stderr,
"No connection within %llu seconds.\n",
static_cast<unsigned long long>( timeout_if_no_client / 1000 ) );
break;
}
network.tick();
} catch ( const Network::NetworkException &e ) {
} catch ( const Network::NetworkException& e ) {
fprintf( stderr, "%s\n", e.what() );
spin();
} catch ( const Crypto::CryptoException &e ) {
} catch ( const Crypto::CryptoException& e ) {
if ( e.fatal ) {
throw;
} else {
@@ -955,22 +959,22 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve
}
}
}
#ifdef HAVE_SYSLOG
syslog(LOG_INFO, "user %s session end", pw->pw_name);
#endif
#ifdef HAVE_SYSLOG
syslog( LOG_INFO, "user %s session end", pw->pw_name );
#endif
}
/* Print the motd from a given file, if available */
static bool print_motd( const char *filename )
static bool print_motd( const char* filename )
{
FILE *motd = fopen( filename, "r" );
FILE* motd = fopen( filename, "r" );
if ( !motd ) {
return false;
}
const int BUFSIZE = 256;
char buffer[ BUFSIZE ];
char buffer[BUFSIZE];
while ( 1 ) {
size_t bytes_read = fread( buffer, 1, BUFSIZE, motd );
if ( bytes_read == 0 ) {
@@ -988,9 +992,9 @@ static bool print_motd( const char *filename )
static void chdir_homedir( void )
{
const char *home = getenv( "HOME" );
const char* home = getenv( "HOME" );
if ( home == NULL ) {
struct passwd *pw = getpwuid( getuid() );
struct passwd* pw = getpwuid( getuid() );
if ( pw == NULL ) {
perror( "getpwuid" );
return; /* non-fatal */
@@ -1015,7 +1019,7 @@ static bool motd_hushed( void )
}
#ifdef HAVE_UTMPX_H
static bool device_exists( const char *ut_line )
static bool device_exists( const char* ut_line )
{
std::string device_name = std::string( "/dev/" ) + std::string( ut_line );
struct stat buf;
@@ -1023,11 +1027,11 @@ static bool device_exists( const char *ut_line )
}
#endif
static void warn_unattached( const std::string & ignore_entry )
static void warn_unattached( const std::string& ignore_entry )
{
#ifdef HAVE_UTMPX_H
/* get username */
const struct passwd *pw = getpwuid( getuid() );
const struct passwd* pw = getpwuid( getuid() );
if ( pw == NULL ) {
perror( "getpwuid" );
/* non-fatal */
@@ -1037,18 +1041,14 @@ static void warn_unattached( const std::string & ignore_entry )
const std::string username( pw->pw_name );
/* look for unattached sessions */
std::vector< std::string > unattached_mosh_servers;
std::vector<std::string> unattached_mosh_servers;
while ( struct utmpx *entry = getutxent() ) {
if ( (entry->ut_type == USER_PROCESS)
&& (username == std::string( entry->ut_user )) ) {
while ( struct utmpx* entry = getutxent() ) {
if ( ( entry->ut_type == USER_PROCESS ) && ( username == std::string( entry->ut_user ) ) ) {
/* does line show unattached mosh session */
std::string text( entry->ut_host );
if ( (text.size() >= 5)
&& (text.substr( 0, 5 ) == "mosh ")
&& (text[ text.size() - 1 ] == ']')
&& (text != ignore_entry)
&& device_exists( entry->ut_line ) ) {
if ( ( text.size() >= 5 ) && ( text.substr( 0, 5 ) == "mosh " ) && ( text[text.size() - 1] == ']' )
&& ( text != ignore_entry ) && device_exists( entry->ut_line ) ) {
unattached_mosh_servers.push_back( text );
}
}
@@ -1063,14 +1063,15 @@ static void warn_unattached( const std::string & ignore_entry )
} else {
std::string pid_string;
for ( std::vector< std::string >::const_iterator it = unattached_mosh_servers.begin();
for ( std::vector<std::string>::const_iterator it = unattached_mosh_servers.begin();
it != unattached_mosh_servers.end();
it++ ) {
pid_string += " - " + *it + "\n";
}
printf( "\033[37;44mMosh: You have %d detached Mosh sessions on this server, with PIDs:\n%s\033[m\n",
(int)unattached_mosh_servers.size(), pid_string.c_str() );
(int)unattached_mosh_servers.size(),
pid_string.c_str() );
}
#endif /* HAVE_UTMPX_H */
}
+64 -60
View File
@@ -52,15 +52,15 @@
#include <util.h>
#endif
#include "stmclient.h"
#include "src/util/swrite.h"
#include "src/statesync/completeterminal.h"
#include "src/statesync/user.h"
#include "src/util/fatal_assert.h"
#include "src/util/locale_utils.h"
#include "src/util/pty_compat.h"
#include "src/util/select.h"
#include "src/util/swrite.h"
#include "src/util/timestamp.h"
#include "stmclient.h"
#include "src/network/networktransport-impl.h"
@@ -85,11 +85,13 @@ void STMClient::init( void )
LocaleVar native_ctype = get_ctype();
std::string native_charset( locale_charset() );
fprintf( stderr, "mosh-client needs a UTF-8 native locale to run.\n\n"
fprintf( stderr,
"mosh-client needs a UTF-8 native locale to run.\n\n"
"Unfortunately, the client's environment (%s) specifies\n"
"the character set \"%s\".\n\n",
native_ctype.str().c_str(), native_charset.c_str() );
int unused __attribute((unused)) = system( "locale" );
native_ctype.str().c_str(),
native_charset.c_str() );
int unused __attribute( ( unused ) ) = system( "locale" );
exit( 1 );
}
@@ -103,7 +105,7 @@ void STMClient::init( void )
raw_termios = saved_termios;
#ifdef HAVE_IUTF8
if ( !(raw_termios.c_iflag & IUTF8) ) {
if ( !( raw_termios.c_iflag & IUTF8 ) ) {
// fprintf( stderr, "Warning: Locale is UTF-8 but termios IUTF8 flag not set. Setting IUTF8 flag.\n" );
/* Probably not really necessary since we are putting terminal driver into raw mode anyway. */
raw_termios.c_iflag |= IUTF8;
@@ -126,8 +128,8 @@ void STMClient::init( void )
}
/* Set terminal escape key. */
const char *escape_key_env;
if ( (escape_key_env = getenv( "MOSH_ESCAPE_KEY" )) != NULL ) {
const char* escape_key_env;
if ( ( escape_key_env = getenv( "MOSH_ESCAPE_KEY" ) ) != NULL ) {
if ( strlen( escape_key_env ) == 1 ) {
escape_key = (int)escape_key_env[0];
if ( escape_key > 0 && escape_key < 128 ) {
@@ -166,7 +168,8 @@ void STMClient::init( void )
/* There are so many better ways to shoot oneself into leg than
setting escape key to Ctrl-C, Ctrl-D, NewLine, Ctrl-L or CarriageReturn
that we just won't allow that. */
if ( escape_key == 0x03 || escape_key == 0x04 || escape_key == 0x0A || escape_key == 0x0C || escape_key == 0x0D ) {
if ( escape_key == 0x03 || escape_key == 0x04 || escape_key == 0x0A || escape_key == 0x0C
|| escape_key == 0x0D ) {
escape_key = 0x1E;
escape_pass_key = '^';
escape_pass_key2 = '^';
@@ -176,23 +179,24 @@ void STMClient::init( void )
if ( escape_key > 0 ) {
char escape_pass_name_buf[16];
char escape_key_name_buf[16];
snprintf(escape_pass_name_buf, sizeof escape_pass_name_buf, "\"%c\"", escape_pass_key);
if (escape_key < 32) {
snprintf(escape_key_name_buf, sizeof escape_key_name_buf, "Ctrl-%c", escape_pass_key);
snprintf( escape_pass_name_buf, sizeof escape_pass_name_buf, "\"%c\"", escape_pass_key );
if ( escape_key < 32 ) {
snprintf( escape_key_name_buf, sizeof escape_key_name_buf, "Ctrl-%c", escape_pass_key );
escape_requires_lf = false;
} else {
snprintf(escape_key_name_buf, sizeof escape_key_name_buf, "\"%c\"", escape_key);
snprintf( escape_key_name_buf, sizeof escape_key_name_buf, "\"%c\"", escape_key );
escape_requires_lf = true;
}
std::string tmp;
tmp = std::string( escape_pass_name_buf );
std::wstring escape_pass_name = std::wstring(tmp.begin(), tmp.end());
std::wstring escape_pass_name = std::wstring( tmp.begin(), tmp.end() );
tmp = std::string( escape_key_name_buf );
std::wstring escape_key_name = std::wstring(tmp.begin(), tmp.end());
escape_key_help = L"Commands: Ctrl-Z suspends, \".\" quits, " + escape_pass_name + L" gives literal " + escape_key_name;
std::wstring escape_key_name = std::wstring( tmp.begin(), tmp.end() );
escape_key_help
= L"Commands: Ctrl-Z suspends, \".\" quits, " + escape_pass_name + L" gives literal " + escape_key_name;
overlays.get_notification_engine().set_escape_key_string( tmp );
}
wchar_t tmp[ 128 ];
wchar_t tmp[128];
swprintf( tmp, 128, L"Nothing received from server on UDP port %s.", port.c_str() );
connecting_notification = std::wstring( tmp );
}
@@ -214,19 +218,24 @@ void STMClient::shutdown( void )
}
if ( still_connecting() ) {
fprintf( stderr, "\nmosh did not make a successful connection to %s:%s.\n"
fprintf( stderr,
"\nmosh did not make a successful connection to %s:%s.\n"
"Please verify that UDP port %s is not firewalled and can reach the server.\n\n"
"(By default, mosh uses a UDP port between 60000 and 61000. The -p option\n"
"selects a specific UDP port number.)\n", ip.c_str(), port.c_str(), port.c_str() );
"selects a specific UDP port number.)\n",
ip.c_str(),
port.c_str(),
port.c_str() );
} else if ( network && !clean_shutdown ) {
fputs( "\n\nmosh did not shut down cleanly. Please note that the\n"
"mosh-server process may still be running on the server.\n", stderr );
"mosh-server process may still be running on the server.\n",
stderr );
}
}
void STMClient::main_init( void )
{
Select &sel = Select::get_instance();
Select& sel = Select::get_instance();
sel.add_signal( SIGWINCH );
sel.add_signal( SIGTERM );
sel.add_signal( SIGINT );
@@ -276,9 +285,7 @@ void STMClient::output_new_frame( void )
overlays.apply( new_state );
/* calculate minimal difference from where we are */
const std::string diff( display.new_frame( !repaint_requested,
local_framebuffer,
new_state ) );
const std::string diff( display.new_frame( !repaint_requested, local_framebuffer, new_state ) );
swrite( STDOUT_FILENO, diff.data(), diff.size() );
repaint_requested = false;
@@ -296,13 +303,14 @@ void STMClient::process_network_input( void )
overlays.get_prediction_engine().set_local_frame_acked( network->get_sent_state_acked() );
overlays.get_prediction_engine().set_send_interval( network->send_interval() );
overlays.get_prediction_engine().set_local_frame_late_acked( network->get_latest_remote_state().state.get_echo_ack() );
overlays.get_prediction_engine().set_local_frame_late_acked(
network->get_latest_remote_state().state.get_echo_ack() );
}
bool STMClient::process_user_input( int fd )
{
const int buf_size = 16384;
char buf[ buf_size ];
char buf[buf_size];
/* fill buffer if possible */
ssize_t bytes_read = read( fd, buf, buf_size );
@@ -313,7 +321,7 @@ bool STMClient::process_user_input( int fd )
return false;
}
NetworkType &net = *network;
NetworkType& net = *network;
if ( net.shutdown_in_progress() ) {
return true;
@@ -327,7 +335,7 @@ bool STMClient::process_user_input( int fd )
}
for ( int i = 0; i < bytes_read; i++ ) {
char the_byte = buf[ i ];
char the_byte = buf[i];
if ( !paste ) {
overlays.get_prediction_engine().new_user_byte( the_byte, local_framebuffer );
@@ -335,8 +343,9 @@ bool STMClient::process_user_input( int fd )
if ( quit_sequence_started ) {
if ( the_byte == '.' ) { /* Quit sequence is Ctrl-^ . */
if ( net.has_remote_addr() && (!net.shutdown_in_progress()) ) {
overlays.get_notification_engine().set_notification_string( std::wstring( L"Exiting on user request..." ), true );
if ( net.has_remote_addr() && ( !net.shutdown_in_progress() ) ) {
overlays.get_notification_engine().set_notification_string( std::wstring( L"Exiting on user request..." ),
true );
net.start_shutdown();
return true;
}
@@ -358,7 +367,7 @@ bool STMClient::process_user_input( int fd )
kill( 0, SIGSTOP );
resume();
} else if ( (the_byte == escape_pass_key) || (the_byte == escape_pass_key2) ) {
} else if ( ( the_byte == escape_pass_key ) || ( the_byte == escape_pass_key2 ) ) {
/* Emulation sequence to type escape_key is escape_key +
escape_pass_key (that is escape key without Ctrl) */
net.get_current_state().push_back( Parser::UserByte( escape_key ) );
@@ -377,14 +386,16 @@ bool STMClient::process_user_input( int fd )
continue;
}
quit_sequence_started = (escape_key > 0) && (the_byte == escape_key) && (lf_entered || (! escape_requires_lf));
quit_sequence_started
= ( escape_key > 0 ) && ( the_byte == escape_key ) && ( lf_entered || ( !escape_requires_lf ) );
if ( quit_sequence_started ) {
lf_entered = false;
overlays.get_notification_engine().set_notification_string( escape_key_help, true, false );
continue;
}
lf_entered = ( (the_byte == 0x0A) || (the_byte == 0x0D) ); /* LineFeed, Ctrl-J, '\n' or CarriageReturn, Ctrl-M, '\r' */
lf_entered = ( ( the_byte == 0x0A )
|| ( the_byte == 0x0D ) ); /* LineFeed, Ctrl-J, '\n' or CarriageReturn, Ctrl-M, '\r' */
if ( the_byte == 0x0C ) { /* Ctrl-L */
repaint_requested = true;
@@ -427,14 +438,14 @@ bool STMClient::main( void )
/* Drop unnecessary privileges */
#ifdef HAVE_PLEDGE
/* OpenBSD pledge() syscall */
if ( pledge( "stdio inet tty", NULL )) {
if ( pledge( "stdio inet tty", NULL ) ) {
perror( "pledge() failed" );
exit( 1 );
}
#endif
/* prepare to poll for events */
Select &sel = Select::get_instance();
Select& sel = Select::get_instance();
while ( 1 ) {
try {
@@ -450,10 +461,8 @@ bool STMClient::main( void )
/* poll for events */
/* network->fd() can in theory change over time */
sel.clear_fds();
std::vector< int > fd_list( network->fds() );
for ( std::vector< int >::const_iterator it = fd_list.begin();
it != fd_list.end();
it++ ) {
std::vector<int> fd_list( network->fds() );
for ( std::vector<int>::const_iterator it = fd_list.begin(); it != fd_list.end(); it++ ) {
sel.add_fd( *it );
}
sel.add_fd( STDIN_FILENO );
@@ -466,9 +475,7 @@ bool STMClient::main( void )
bool network_ready_to_read = false;
for ( std::vector< int >::const_iterator it = fd_list.begin();
it != fd_list.end();
it++ ) {
for ( std::vector<int>::const_iterator it = fd_list.begin(); it != fd_list.end(); it++ ) {
if ( sel.read( *it ) ) {
/* packet received from the network */
/* we only read one socket each run */
@@ -480,7 +487,8 @@ bool STMClient::main( void )
process_network_input();
}
if ( sel.read( STDIN_FILENO ) && !process_user_input( STDIN_FILENO ) ) { /* input from the user needs to be fed to the network */
if ( sel.read( STDIN_FILENO )
&& !process_user_input( STDIN_FILENO ) ) { /* input from the user needs to be fed to the network */
if ( !network->has_remote_addr() ) {
break;
} else if ( !network->shutdown_in_progress() ) {
@@ -497,15 +505,13 @@ bool STMClient::main( void )
resume();
}
if ( sel.signal( SIGTERM )
|| sel.signal( SIGINT )
|| sel.signal( SIGHUP )
|| sel.signal( SIGPIPE ) ) {
if ( sel.signal( SIGTERM ) || sel.signal( SIGINT ) || sel.signal( SIGHUP ) || sel.signal( SIGPIPE ) ) {
/* shutdown signal */
if ( !network->has_remote_addr() ) {
break;
} else if ( !network->shutdown_in_progress() ) {
overlays.get_notification_engine().set_notification_string( std::wstring( L"Signal received, shutting down..." ), true );
overlays.get_notification_engine().set_notification_string(
std::wstring( L"Signal received, shutting down..." ), true );
network->start_shutdown();
}
}
@@ -528,33 +534,32 @@ bool STMClient::main( void )
}
/* write diagnostic message if can't reach server */
if ( still_connecting()
&& (!network->shutdown_in_progress())
&& (timestamp() - network->get_latest_remote_state().timestamp > 250) ) {
if ( still_connecting() && ( !network->shutdown_in_progress() )
&& ( timestamp() - network->get_latest_remote_state().timestamp > 250 ) ) {
if ( timestamp() - network->get_latest_remote_state().timestamp > 15000 ) {
if ( !network->shutdown_in_progress() ) {
overlays.get_notification_engine().set_notification_string( std::wstring( L"Timed out waiting for server..." ), true );
overlays.get_notification_engine().set_notification_string(
std::wstring( L"Timed out waiting for server..." ), true );
network->start_shutdown();
}
} else {
overlays.get_notification_engine().set_notification_string( connecting_notification );
}
} else if ( (network->get_remote_state_num() != 0)
&& (overlays.get_notification_engine().get_notification_string()
== connecting_notification) ) {
} else if ( ( network->get_remote_state_num() != 0 )
&& ( overlays.get_notification_engine().get_notification_string() == connecting_notification ) ) {
overlays.get_notification_engine().set_notification_string( L"" );
}
network->tick();
std::string & send_error = network->get_send_error();
std::string& send_error = network->get_send_error();
if ( !send_error.empty() ) {
overlays.get_notification_engine().set_network_error( send_error );
send_error.clear();
} else {
overlays.get_notification_engine().clear_network_error();
}
} catch ( const Network::NetworkException &e ) {
} catch ( const Network::NetworkException& e ) {
if ( !network->shutdown_in_progress() ) {
overlays.get_notification_engine().set_network_error( e.what() );
}
@@ -564,11 +569,11 @@ bool STMClient::main( void )
req.tv_nsec = 200000000; /* 0.2 sec */
nanosleep( &req, NULL );
freeze_timestamp();
} catch ( const Crypto::CryptoException &e ) {
} catch ( const Crypto::CryptoException& e ) {
if ( e.fatal ) {
throw;
} else {
wchar_t tmp[ 128 ];
wchar_t tmp[128];
swprintf( tmp, 128, L"Crypto exception: %s", e.what() );
overlays.get_notification_engine().set_notification_string( std::wstring( tmp ) );
}
@@ -576,4 +581,3 @@ bool STMClient::main( void )
}
return clean_shutdown;
}
+20 -25
View File
@@ -33,18 +33,19 @@
#ifndef STM_CLIENT_HPP
#define STM_CLIENT_HPP
#include <string>
#include <memory>
#include <string>
#include <sys/ioctl.h>
#include <termios.h>
#include "src/statesync/completeterminal.h"
#include "src/network/networktransport.h"
#include "src/statesync/user.h"
#include "src/frontend/terminaloverlay.h"
#include "src/network/networktransport.h"
#include "src/statesync/completeterminal.h"
#include "src/statesync/user.h"
class STMClient {
class STMClient
{
private:
std::string ip;
std::string port;
@@ -88,24 +89,18 @@ private:
void resume( void ); /* restore state after SIGCONT */
public:
STMClient( const char *s_ip, const char *s_port, const char *s_key, const char *predict_mode, unsigned int s_verbose, const char *predict_overwrite )
: ip( s_ip ? s_ip : "" ), port( s_port ? s_port : "" ),
key( s_key ? s_key : "" ),
escape_key( 0x1E ), escape_pass_key( '^' ), escape_pass_key2( '^' ),
escape_requires_lf( false ), escape_key_help( L"?" ),
saved_termios(), raw_termios(),
window_size(),
local_framebuffer( 1, 1 ),
new_state( 1, 1 ),
overlays(),
network(),
display( true ), /* use TERM environment var to initialize display */
connecting_notification(),
repaint_requested( false ),
lf_entered( false ),
quit_sequence_started( false ),
clean_shutdown( false ),
verbose( s_verbose )
STMClient( const char* s_ip,
const char* s_port,
const char* s_key,
const char* predict_mode,
unsigned int s_verbose,
const char* predict_overwrite )
: ip( s_ip ? s_ip : "" ), port( s_port ? s_port : "" ), key( s_key ? s_key : "" ), escape_key( 0x1E ),
escape_pass_key( '^' ), escape_pass_key2( '^' ), escape_requires_lf( false ), escape_key_help( L"?" ),
saved_termios(), raw_termios(), window_size(), local_framebuffer( 1, 1 ), new_state( 1, 1 ), overlays(),
network(), display( true ), /* use TERM environment var to initialize display */
connecting_notification(), repaint_requested( false ), lf_entered( false ), quit_sequence_started( false ),
clean_shutdown( false ), verbose( s_verbose )
{
if ( predict_mode ) {
if ( !strcmp( predict_mode, "always" ) ) {
@@ -131,8 +126,8 @@ public:
bool main( void );
/* unused */
STMClient( const STMClient & );
STMClient & operator=( const STMClient & );
STMClient( const STMClient& );
STMClient& operator=( const STMClient& );
};
#endif
+109 -149
View File
@@ -40,11 +40,9 @@
using namespace Overlay;
void ConditionalOverlayCell::apply( Framebuffer &fb, uint64_t confirmed_epoch, int row, bool flag ) const
void ConditionalOverlayCell::apply( Framebuffer& fb, uint64_t confirmed_epoch, int row, bool flag ) const
{
if ( (!active)
|| (row >= fb.ds.get_height())
|| (col >= fb.ds.get_width()) ) {
if ( ( !active ) || ( row >= fb.ds.get_height() ) || ( col >= fb.ds.get_width() ) ) {
return;
}
@@ -58,33 +56,33 @@ void ConditionalOverlayCell::apply( Framebuffer &fb, uint64_t confirmed_epoch, i
if ( unknown ) {
if ( flag && ( col != fb.ds.get_width() - 1 ) ) {
fb.get_mutable_cell( row, col )->get_renditions().set_attribute(Renditions::underlined, true);
fb.get_mutable_cell( row, col )->get_renditions().set_attribute( Renditions::underlined, true );
}
return;
}
if ( *fb.get_cell( row, col ) != replacement ) {
*(fb.get_mutable_cell( row, col )) = replacement;
*( fb.get_mutable_cell( row, col ) ) = replacement;
if ( flag ) {
fb.get_mutable_cell( row, col )->get_renditions().set_attribute( Renditions::underlined, true );
}
}
}
Validity ConditionalOverlayCell::get_validity( const Framebuffer &fb, int row,
uint64_t early_ack __attribute__((unused)),
Validity ConditionalOverlayCell::get_validity( const Framebuffer& fb,
int row,
uint64_t early_ack __attribute__( ( unused ) ),
uint64_t late_ack ) const
{
if ( !active ) {
return Inactive;
}
if ( (row >= fb.ds.get_height())
|| (col >= fb.ds.get_width()) ) {
if ( ( row >= fb.ds.get_height() ) || ( col >= fb.ds.get_width() ) ) {
return IncorrectOrExpired;
}
const Cell &current = *( fb.get_cell( row, col ) );
const Cell& current = *( fb.get_cell( row, col ) );
/* see if it hasn't been updated yet */
if ( late_ack < expiration_frame ) {
@@ -113,23 +111,21 @@ Validity ConditionalOverlayCell::get_validity( const Framebuffer &fb, int row,
return IncorrectOrExpired;
}
Validity ConditionalCursorMove::get_validity( const Framebuffer &fb,
uint64_t early_ack __attribute((unused)),
Validity ConditionalCursorMove::get_validity( const Framebuffer& fb,
uint64_t early_ack __attribute( ( unused ) ),
uint64_t late_ack ) const
{
if ( !active ) {
return Inactive;
}
if ( (row >= fb.ds.get_height())
|| (col >= fb.ds.get_width()) ) {
if ( ( row >= fb.ds.get_height() ) || ( col >= fb.ds.get_width() ) ) {
// fprintf( stderr, "Crazy cursor (%d,%d)!\n", row, col );
return IncorrectOrExpired;
}
if ( late_ack >= expiration_frame ) {
if ( (fb.ds.get_cursor_col() == col)
&& (fb.ds.get_cursor_row() == row) ) {
if ( ( fb.ds.get_cursor_col() == col ) && ( fb.ds.get_cursor_row() == row ) ) {
return Correct;
}
return IncorrectOrExpired;
@@ -138,7 +134,7 @@ Validity ConditionalCursorMove::get_validity( const Framebuffer &fb,
return Pending;
}
void ConditionalCursorMove::apply( Framebuffer &fb, uint64_t confirmed_epoch ) const
void ConditionalCursorMove::apply( Framebuffer& fb, uint64_t confirmed_epoch ) const
{
if ( !active ) {
return;
@@ -157,29 +153,24 @@ void ConditionalCursorMove::apply( Framebuffer &fb, uint64_t confirmed_epoch ) c
}
NotificationEngine::NotificationEngine()
: last_word_from_server( timestamp() ),
last_acked_state( timestamp() ),
escape_key_string(),
message(),
message_is_network_error( false ),
message_expiration( -1 ),
show_quit_keystroke( true )
: last_word_from_server( timestamp() ), last_acked_state( timestamp() ), escape_key_string(), message(),
message_is_network_error( false ), message_expiration( -1 ), show_quit_keystroke( true )
{}
static std::string human_readable_duration( int num_seconds, const std::string &seconds_abbr ) {
char tmp[ 128 ];
static std::string human_readable_duration( int num_seconds, const std::string& seconds_abbr )
{
char tmp[128];
if ( num_seconds < 60 ) {
snprintf( tmp, 128, "%d %s", num_seconds, seconds_abbr.c_str() );
} else if ( num_seconds < 3600 ) {
snprintf( tmp, 128, "%d:%02d", num_seconds / 60, num_seconds % 60 );
} else {
snprintf( tmp, 128, "%d:%02d:%02d", num_seconds / 3600,
(num_seconds / 60) % 60, num_seconds % 60 );
snprintf( tmp, 128, "%d:%02d:%02d", num_seconds / 3600, ( num_seconds / 60 ) % 60, num_seconds % 60 );
}
return tmp;
}
void NotificationEngine::apply( Framebuffer &fb ) const
void NotificationEngine::apply( Framebuffer& fb ) const
{
uint64_t now = timestamp();
@@ -204,55 +195,60 @@ void NotificationEngine::apply( Framebuffer &fb ) const
notification_bar.append( 0x20 );
for ( int i = 0; i < fb.ds.get_width(); i++ ) {
*(fb.get_mutable_cell( 0, i )) = notification_bar;
*( fb.get_mutable_cell( 0, i ) ) = notification_bar;
}
/* write message */
wchar_t tmp[ 128 ];
wchar_t tmp[128];
/* We want to prefer the "last contact" message if we simply haven't
heard from the server in a while, but print the "last reply" message
if the problem is uplink-only. */
double since_heard = (double)(now - last_word_from_server) / 1000.0;
double since_ack = (double)(now - last_acked_state) / 1000.0;
double since_heard = (double)( now - last_word_from_server ) / 1000.0;
double since_ack = (double)( now - last_acked_state ) / 1000.0;
const char server_message[] = "contact";
const char reply_message[] = "reply";
double time_elapsed = since_heard;
const char *explanation = server_message;
const char* explanation = server_message;
if ( reply_late( now ) && (!server_late( now )) ) {
if ( reply_late( now ) && ( !server_late( now ) ) ) {
time_elapsed = since_ack;
explanation = reply_message;
}
const static char blank[] = "";
const char *keystroke_str = show_quit_keystroke ? escape_key_string.c_str() : blank;
const char* keystroke_str = show_quit_keystroke ? escape_key_string.c_str() : blank;
if ( message.empty() && (!time_expired) ) {
if ( message.empty() && ( !time_expired ) ) {
return;
}
if ( message.empty() && time_expired ) {
swprintf( tmp, 128, L"mosh: Last %s %s ago.%s", explanation,
human_readable_duration( static_cast<int>( time_elapsed ),
"seconds" ).c_str(),
swprintf( tmp,
128,
L"mosh: Last %s %s ago.%s",
explanation,
human_readable_duration( static_cast<int>( time_elapsed ), "seconds" ).c_str(),
keystroke_str );
} else if ( (!message.empty()) && (!time_expired) ) {
} else if ( ( !message.empty() ) && ( !time_expired ) ) {
swprintf( tmp, 128, L"mosh: %ls%s", message.c_str(), keystroke_str );
} else {
swprintf( tmp, 128, L"mosh: %ls (%s without %s.)%s", message.c_str(),
human_readable_duration( static_cast<int>( time_elapsed ),
"s" ).c_str(),
explanation, keystroke_str );
swprintf( tmp,
128,
L"mosh: %ls (%s without %s.)%s",
message.c_str(),
human_readable_duration( static_cast<int>( time_elapsed ), "s" ).c_str(),
explanation,
keystroke_str );
}
std::wstring string_to_draw( tmp );
int overlay_col = 0;
Cell *combining_cell = fb.get_mutable_cell( 0, 0 );
Cell* combining_cell = fb.get_mutable_cell( 0, 0 );
/* We unfortunately duplicate the terminal's logic for how to render a Unicode sequence into graphemes */
for ( std::wstring::const_iterator i = string_to_draw.begin(); i != string_to_draw.end(); i++ ) {
@@ -262,14 +258,14 @@ void NotificationEngine::apply( Framebuffer &fb ) const
wchar_t ch = *i;
int chwidth = ch == L'\0' ? -1 : wcwidth( ch );
Cell *this_cell = 0;
Cell* this_cell = 0;
switch ( chwidth ) {
case 1: /* normal character */
case 2: /* wide character */
this_cell = fb.get_mutable_cell( 0, overlay_col );
fb.reset_cell( this_cell );
this_cell->get_renditions().set_attribute(Renditions::bold, true);
this_cell->get_renditions().set_attribute( Renditions::bold, true );
this_cell->get_renditions().set_foreground_color( 7 );
this_cell->get_renditions().set_background_color( 4 );
@@ -330,7 +326,7 @@ int NotificationEngine::wait_time( void ) const
return next_expiry;
}
void OverlayManager::apply( Framebuffer &fb )
void OverlayManager::apply( Framebuffer& fb )
{
predictions.cull( fb );
predictions.apply( fb );
@@ -339,65 +335,52 @@ void OverlayManager::apply( Framebuffer &fb )
title.apply( fb );
}
void TitleEngine::set_prefix( const std::wstring &s )
void TitleEngine::set_prefix( const std::wstring& s )
{
prefix = Terminal::Framebuffer::title_type( s.begin(), s.end() );
}
void ConditionalOverlayRow::apply( Framebuffer &fb, uint64_t confirmed_epoch, bool flag ) const
void ConditionalOverlayRow::apply( Framebuffer& fb, uint64_t confirmed_epoch, bool flag ) const
{
for ( overlay_cells_type::const_iterator it = overlay_cells.begin();
it != overlay_cells.end();
it++ ) {
for ( overlay_cells_type::const_iterator it = overlay_cells.begin(); it != overlay_cells.end(); it++ ) {
it->apply( fb, confirmed_epoch, row_num, flag );
}
}
void PredictionEngine::apply( Framebuffer &fb ) const
void PredictionEngine::apply( Framebuffer& fb ) const
{
if ( (display_preference == Never) || !( srtt_trigger
|| glitch_trigger
|| (display_preference == Always)
|| (display_preference == Experimental) ) ){
if ( ( display_preference == Never )
|| !( srtt_trigger || glitch_trigger || ( display_preference == Always )
|| ( display_preference == Experimental ) ) ) {
return;
}
for ( cursors_type::const_iterator it = cursors.begin();
it != cursors.end();
it++ ) {
for ( cursors_type::const_iterator it = cursors.begin(); it != cursors.end(); it++ ) {
it->apply( fb, confirmed_epoch );
}
for ( overlays_type::const_iterator it = overlays.begin();
it != overlays.end();
it++ ) {
for ( overlays_type::const_iterator it = overlays.begin(); it != overlays.end(); it++ ) {
it->apply( fb, confirmed_epoch, flagging );
}
}
void PredictionEngine::kill_epoch( uint64_t epoch, const Framebuffer &fb )
void PredictionEngine::kill_epoch( uint64_t epoch, const Framebuffer& fb )
{
for( cursors_type::iterator it = cursors.begin(); it != cursors.end(); ) {
for ( cursors_type::iterator it = cursors.begin(); it != cursors.end(); ) {
cursors_type::iterator it_next = it;
it_next++;
if ( it->tentative( epoch - 1 )) {
if ( it->tentative( epoch - 1 ) ) {
cursors.erase( it );
}
it = it_next;
}
cursors.push_back( ConditionalCursorMove( local_frame_sent + 1,
fb.ds.get_cursor_row(),
fb.ds.get_cursor_col(),
prediction_epoch ) );
cursors.push_back( ConditionalCursorMove(
local_frame_sent + 1, fb.ds.get_cursor_row(), fb.ds.get_cursor_col(), prediction_epoch ) );
cursor().active = true;
for ( overlays_type::iterator i = overlays.begin();
i != overlays.end();
i++ ) {
for ( overlay_cells_type::iterator j = i->overlay_cells.begin();
j != i->overlay_cells.end();
j++ ) {
for ( overlays_type::iterator i = overlays.begin(); i != overlays.end(); i++ ) {
for ( overlay_cells_type::iterator j = i->overlay_cells.begin(); j != i->overlay_cells.end(); j++ ) {
if ( j->tentative( epoch - 1 ) ) {
j->reset();
}
@@ -416,35 +399,30 @@ void PredictionEngine::reset( void )
// fprintf( stderr, "RESETTING\n" );
}
void PredictionEngine::init_cursor( const Framebuffer &fb )
void PredictionEngine::init_cursor( const Framebuffer& fb )
{
if ( cursors.empty() ) {
/* initialize new cursor prediction */
cursors.push_back( ConditionalCursorMove( local_frame_sent + 1,
fb.ds.get_cursor_row(),
fb.ds.get_cursor_col(),
prediction_epoch ) );
cursors.push_back( ConditionalCursorMove(
local_frame_sent + 1, fb.ds.get_cursor_row(), fb.ds.get_cursor_col(), prediction_epoch ) );
cursor().active = true;
} else if ( cursor().tentative_until_epoch != prediction_epoch ) {
cursors.push_back( ConditionalCursorMove( local_frame_sent + 1,
cursor().row,
cursor().col,
prediction_epoch ) );
cursors.push_back(
ConditionalCursorMove( local_frame_sent + 1, cursor().row, cursor().col, prediction_epoch ) );
cursor().active = true;
}
}
void PredictionEngine::cull( const Framebuffer &fb )
void PredictionEngine::cull( const Framebuffer& fb )
{
if ( display_preference == Never ) {
return;
}
if ( (last_height != fb.ds.get_height())
|| (last_width != fb.ds.get_width()) ) {
if ( ( last_height != fb.ds.get_height() ) || ( last_width != fb.ds.get_width() ) ) {
last_height = fb.ds.get_height();
last_width = fb.ds.get_width();
reset();
@@ -455,9 +433,8 @@ void PredictionEngine::cull( const Framebuffer &fb )
/* control srtt_trigger with hysteresis */
if ( send_interval > SRTT_TRIGGER_HIGH ) {
srtt_trigger = true;
} else if ( srtt_trigger &&
(send_interval <= SRTT_TRIGGER_LOW) /* 20 ms is current minimum value */
&& (!active()) ) { /* only turn off when no predictions being shown */
} else if ( srtt_trigger && ( send_interval <= SRTT_TRIGGER_LOW ) /* 20 ms is current minimum value */
&& ( !active() ) ) { /* only turn off when no predictions being shown */
srtt_trigger = false;
}
@@ -479,17 +456,14 @@ void PredictionEngine::cull( const Framebuffer &fb )
while ( i != overlays.end() ) {
overlays_type::iterator inext = i;
inext++;
if ( (i->row_num < 0) || (i->row_num >= fb.ds.get_height()) ) {
if ( ( i->row_num < 0 ) || ( i->row_num >= fb.ds.get_height() ) ) {
overlays.erase( i );
i = inext;
continue;
}
for ( overlay_cells_type::iterator j = i->overlay_cells.begin();
j != i->overlay_cells.end();
j++ ) {
switch ( j->get_validity( fb, i->row_num,
local_frame_acked, local_frame_late_acked ) ) {
for ( overlay_cells_type::iterator j = i->overlay_cells.begin(); j != i->overlay_cells.end(); j++ ) {
switch ( j->get_validity( fb, i->row_num, local_frame_acked, local_frame_late_acked ) ) {
case IncorrectOrExpired:
if ( j->tentative( confirmed_epoch ) ) {
@@ -548,7 +522,6 @@ void PredictionEngine::cull( const Framebuffer &fb )
j->replacement.debug_contents(), i->row_num, j->col,
confirmed_epoch, prediction_epoch );
*/
}
/* When predictions come in quickly, slowly take away the glitch trigger. */
@@ -560,10 +533,8 @@ void PredictionEngine::cull( const Framebuffer &fb )
/* match rest of row to the actual renditions */
{
const Renditions &actual_renditions = fb.get_cell( i->row_num, j->col )->get_renditions();
for ( overlay_cells_type::iterator k = j;
k != i->overlay_cells.end();
k++ ) {
const Renditions& actual_renditions = fb.get_cell( i->row_num, j->col )->get_renditions();
for ( overlay_cells_type::iterator k = j; k != i->overlay_cells.end(); k++ ) {
k->replacement.get_renditions() = actual_renditions;
}
}
@@ -576,10 +547,10 @@ void PredictionEngine::cull( const Framebuffer &fb )
case Pending:
/* When a prediction takes a long time to be confirmed, we
activate the predictions even if SRTT is low */
if ( (now - j->prediction_time) >= GLITCH_FLAG_THRESHOLD ) {
if ( ( now - j->prediction_time ) >= GLITCH_FLAG_THRESHOLD ) {
glitch_trigger = GLITCH_REPAIR_COUNT * 2; /* display and underline */
} else if ( ((now - j->prediction_time) >= GLITCH_THRESHOLD)
&& (glitch_trigger < GLITCH_REPAIR_COUNT) ) {
} else if ( ( ( now - j->prediction_time ) >= GLITCH_THRESHOLD )
&& ( glitch_trigger < GLITCH_REPAIR_COUNT ) ) {
glitch_trigger = GLITCH_REPAIR_COUNT; /* just display */
}
@@ -594,8 +565,7 @@ void PredictionEngine::cull( const Framebuffer &fb )
/* go through cursor predictions */
if ( !cursors.empty()
&& cursor().get_validity( fb,
local_frame_acked, local_frame_late_acked ) == IncorrectOrExpired ) {
&& cursor().get_validity( fb, local_frame_acked, local_frame_late_acked ) == IncorrectOrExpired ) {
/*
fprintf( stderr, "Sadly, we're predicting (%d,%d) vs. (%d,%d) [tau: %ld, expiration_time=%ld, now=%ld]\n",
cursor().row, cursor().col,
@@ -615,8 +585,7 @@ void PredictionEngine::cull( const Framebuffer &fb )
/* NB: switching from list to another STL container could break this code.
So we don't use the cursors_type typedef. */
for ( std::list<ConditionalCursorMove>::iterator it = cursors.begin();
it != cursors.end(); ) {
for ( std::list<ConditionalCursorMove>::iterator it = cursors.begin(); it != cursors.end(); ) {
if ( it->get_validity( fb, local_frame_acked, local_frame_late_acked ) != Pending ) {
it = cursors.erase( it );
} else {
@@ -625,7 +594,7 @@ void PredictionEngine::cull( const Framebuffer &fb )
}
}
ConditionalOverlayRow & PredictionEngine::get_or_make_row( int row_num, int num_cols )
ConditionalOverlayRow& PredictionEngine::get_or_make_row( int row_num, int num_cols )
{
overlays_type::iterator it;
@@ -643,13 +612,13 @@ ConditionalOverlayRow & PredictionEngine::get_or_make_row( int row_num, int num_
r.overlay_cells.reserve( num_cols );
for ( int i = 0; i < num_cols; i++ ) {
r.overlay_cells.push_back( ConditionalOverlayCell( 0, i, prediction_epoch ) );
assert( r.overlay_cells[ i ].col == i );
assert( r.overlay_cells[i].col == i );
}
overlays.push_back( r );
return overlays.back();
}
void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
void PredictionEngine::new_user_byte( char the_byte, const Framebuffer& fb )
{
if ( display_preference == Never ) {
return;
@@ -663,8 +632,7 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
uint64_t now = timestamp();
/* translate application-mode cursor control function to ANSI cursor control sequence */
if ( (last_byte == 0x1b)
&& (the_byte == 'O') ) {
if ( ( last_byte == 0x1b ) && ( the_byte == 'O' ) ) {
the_byte = '[';
}
last_byte = the_byte;
@@ -672,9 +640,7 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
Parser::Actions actions;
parser.input( the_byte, actions );
for ( Parser::Actions::iterator it = actions.begin();
it != actions.end();
it++ ) {
for ( Parser::Actions::iterator it = actions.begin(); it != actions.end(); it++ ) {
Parser::Action& act = **it;
/*
@@ -695,14 +661,14 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
if ( ch == 0x7f ) { /* backspace */
// fprintf( stderr, "Backspace.\n" );
ConditionalOverlayRow &the_row = get_or_make_row( cursor().row, fb.ds.get_width() );
ConditionalOverlayRow& the_row = get_or_make_row( cursor().row, fb.ds.get_width() );
if ( cursor().col > 0 ) {
cursor().col--;
cursor().expire( local_frame_sent + 1, now );
if ( predict_overwrite ) {
ConditionalOverlayCell &cell = the_row.overlay_cells[ cursor().col ];
ConditionalOverlayCell& cell = the_row.overlay_cells[cursor().col];
cell.reset_with_orig();
cell.active = true;
cell.tentative_until_epoch = prediction_epoch;
@@ -711,10 +677,10 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
cell.original_contents.push_back( orig_cell );
cell.replacement = orig_cell;
cell.replacement.clear();
cell.replacement.append(' ');
cell.replacement.append( ' ' );
} else {
for ( int i = cursor().col; i < fb.ds.get_width(); i++ ) {
ConditionalOverlayCell &cell = the_row.overlay_cells[ i ];
ConditionalOverlayCell& cell = the_row.overlay_cells[i];
cell.reset_with_orig();
cell.active = true;
@@ -723,8 +689,8 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
cell.original_contents.push_back( *fb.get_cell( cursor().row, i ) );
if ( i + 2 < fb.ds.get_width() ) {
ConditionalOverlayCell &next_cell = the_row.overlay_cells[ i + 1 ];
const Cell *next_cell_actual = fb.get_cell( cursor().row, i + 1 );
ConditionalOverlayCell& next_cell = the_row.overlay_cells[i + 1];
const Cell* next_cell_actual = fb.get_cell( cursor().row, i + 1 );
if ( next_cell.active ) {
if ( next_cell.unknown ) {
@@ -743,7 +709,7 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
}
}
}
} else if ( (ch < 0x20) || (wcwidth( ch ) != 1) ) {
} else if ( ( ch < 0x20 ) || ( wcwidth( ch ) != 1 ) ) {
/* unknown print */
become_tentative();
// fprintf( stderr, "Unknown print 0x%x\n", ch );
@@ -753,7 +719,7 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
assert( cursor().row < fb.ds.get_height() );
assert( cursor().col < fb.ds.get_width() );
ConditionalOverlayRow &the_row = get_or_make_row( cursor().row, fb.ds.get_width() );
ConditionalOverlayRow& the_row = get_or_make_row( cursor().row, fb.ds.get_width() );
if ( cursor().col + 1 >= fb.ds.get_width() ) {
/* prediction in the last column is tricky */
@@ -764,15 +730,15 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
/* do the insert */
int rightmost_column = predict_overwrite ? cursor().col : fb.ds.get_width() - 1;
for ( int i = rightmost_column; i > cursor().col; i-- ) {
ConditionalOverlayCell &cell = the_row.overlay_cells[ i ];
ConditionalOverlayCell& cell = the_row.overlay_cells[i];
cell.reset_with_orig();
cell.active = true;
cell.tentative_until_epoch = prediction_epoch;
cell.expire( local_frame_sent + 1, now );
cell.original_contents.push_back( *fb.get_cell( cursor().row, i ) );
ConditionalOverlayCell &prev_cell = the_row.overlay_cells[ i - 1 ];
const Cell *prev_cell_actual = fb.get_cell( cursor().row, i - 1 );
ConditionalOverlayCell& prev_cell = the_row.overlay_cells[i - 1];
const Cell* prev_cell_actual = fb.get_cell( cursor().row, i - 1 );
if ( i == fb.ds.get_width() - 1 ) {
cell.unknown = true;
@@ -789,7 +755,7 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
}
}
ConditionalOverlayCell &cell = the_row.overlay_cells[ cursor().col ];
ConditionalOverlayCell& cell = the_row.overlay_cells[cursor().col];
cell.reset_with_orig();
cell.active = true;
cell.tentative_until_epoch = prediction_epoch;
@@ -798,9 +764,9 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
/* heuristic: match renditions of character to the left */
if ( cursor().col > 0 ) {
ConditionalOverlayCell &prev_cell = the_row.overlay_cells[ cursor().col - 1 ];
const Cell *prev_cell_actual = fb.get_cell( cursor().row, cursor().col - 1 );
if ( prev_cell.active && (!prev_cell.unknown) ) {
ConditionalOverlayCell& prev_cell = the_row.overlay_cells[cursor().col - 1];
const Cell* prev_cell_actual = fb.get_cell( cursor().row, cursor().col - 1 );
if ( prev_cell.active && ( !prev_cell.unknown ) ) {
cell.replacement.get_renditions() = prev_cell.replacement.get_renditions();
} else {
cell.replacement.get_renditions() = prev_cell_actual->get_renditions();
@@ -829,7 +795,7 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
}
}
} else if ( type_act == typeid( Parser::Execute ) ) {
if ( act.char_present && (act.ch == 0x0d) /* CR */ ) {
if ( act.char_present && ( act.ch == 0x0d ) /* CR */ ) {
become_tentative();
newline_carriage_return( fb );
} else {
@@ -840,13 +806,13 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
// fprintf( stderr, "Escape sequence\n" );
become_tentative();
} else if ( type_act == typeid( Parser::CSI_Dispatch ) ) {
if ( act.char_present && (act.ch == L'C') ) { /* right arrow */
if ( act.char_present && ( act.ch == L'C' ) ) { /* right arrow */
init_cursor( fb );
if ( cursor().col < fb.ds.get_width() - 1 ) {
cursor().col++;
cursor().expire( local_frame_sent + 1, now );
}
} else if ( act.char_present && (act.ch == L'D') ) { /* left arrow */
} else if ( act.char_present && ( act.ch == L'D' ) ) { /* left arrow */
init_cursor( fb );
if ( cursor().col > 0 ) {
@@ -861,7 +827,7 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
}
}
void PredictionEngine::newline_carriage_return( const Framebuffer &fb )
void PredictionEngine::newline_carriage_return( const Framebuffer& fb )
{
uint64_t now = timestamp();
init_cursor( fb );
@@ -884,10 +850,8 @@ void PredictionEngine::newline_carriage_return( const Framebuffer &fb )
*/
/* make blank prediction for last row */
ConditionalOverlayRow &the_row = get_or_make_row( cursor().row, fb.ds.get_width() );
for ( overlay_cells_type::iterator j = the_row.overlay_cells.begin();
j != the_row.overlay_cells.end();
j++ ) {
ConditionalOverlayRow& the_row = get_or_make_row( cursor().row, fb.ds.get_width() );
for ( overlay_cells_type::iterator j = the_row.overlay_cells.begin(); j != the_row.overlay_cells.end(); j++ ) {
j->active = true;
j->tentative_until_epoch = prediction_epoch;
j->expire( local_frame_sent + 1, now );
@@ -916,12 +880,8 @@ bool PredictionEngine::active( void ) const
return true;
}
for ( overlays_type::const_iterator i = overlays.begin();
i != overlays.end();
i++ ) {
for ( overlay_cells_type::const_iterator j = i->overlay_cells.begin();
j != i->overlay_cells.end();
j++ ) {
for ( overlays_type::const_iterator i = overlays.begin(); i != overlays.end(); i++ ) {
for ( overlay_cells_type::const_iterator j = i->overlay_cells.begin(); j != i->overlay_cells.end(); j++ ) {
if ( j->active ) {
return true;
}
+111 -103
View File
@@ -33,28 +33,30 @@
#ifndef TERMINAL_OVERLAY_HPP
#define TERMINAL_OVERLAY_HPP
#include "src/terminal/terminalframebuffer.h"
#include "src/network/network.h"
#include "src/network/transportsender.h"
#include "src/terminal/parser.h"
#include "src/terminal/terminalframebuffer.h"
#include <climits>
#include <vector>
namespace Overlay {
using namespace Terminal;
using namespace Network;
using namespace Terminal;
using namespace Network;
enum Validity {
enum Validity
{
Pending,
Correct,
CorrectNoCredit,
IncorrectOrExpired,
Inactive
};
};
class ConditionalOverlay {
public:
class ConditionalOverlay
{
public:
uint64_t expiration_frame;
int col;
bool active; /* represents a prediction at all */
@@ -62,55 +64,64 @@ namespace Overlay {
uint64_t prediction_time; /* used to find long-pending predictions */
ConditionalOverlay( uint64_t s_exp, int s_col, uint64_t s_tentative )
: expiration_frame( s_exp ), col( s_col ),
active( false ),
tentative_until_epoch( s_tentative ), prediction_time( uint64_t( -1 ) )
: expiration_frame( s_exp ), col( s_col ), active( false ), tentative_until_epoch( s_tentative ),
prediction_time( uint64_t( -1 ) )
{}
virtual ~ConditionalOverlay() {}
bool tentative( uint64_t confirmed_epoch ) const { return tentative_until_epoch > confirmed_epoch; }
void reset( void ) { expiration_frame = tentative_until_epoch = -1; active = false; }
void reset( void )
{
expiration_frame = tentative_until_epoch = -1;
active = false;
}
void expire( uint64_t s_exp, uint64_t now )
{
expiration_frame = s_exp; prediction_time = now;
expiration_frame = s_exp;
prediction_time = now;
}
};
};
class ConditionalCursorMove : public ConditionalOverlay {
public:
class ConditionalCursorMove : public ConditionalOverlay
{
public:
int row;
void apply( Framebuffer &fb, uint64_t confirmed_epoch ) const;
void apply( Framebuffer& fb, uint64_t confirmed_epoch ) const;
Validity get_validity( const Framebuffer &fb, uint64_t early_ack, uint64_t late_ack ) const;
Validity get_validity( const Framebuffer& fb, uint64_t early_ack, uint64_t late_ack ) const;
ConditionalCursorMove( uint64_t s_exp, int s_row, int s_col, uint64_t s_tentative )
: ConditionalOverlay( s_exp, s_col, s_tentative ), row( s_row )
{}
};
};
class ConditionalOverlayCell : public ConditionalOverlay {
public:
class ConditionalOverlayCell : public ConditionalOverlay
{
public:
Cell replacement;
bool unknown;
std::vector<Cell> original_contents; /* we don't give credit for correct predictions
that match the original contents */
void apply( Framebuffer &fb, uint64_t confirmed_epoch, int row, bool flag ) const;
Validity get_validity( const Framebuffer &fb, int row, uint64_t early_ack, uint64_t late_ack ) const;
void apply( Framebuffer& fb, uint64_t confirmed_epoch, int row, bool flag ) const;
Validity get_validity( const Framebuffer& fb, int row, uint64_t early_ack, uint64_t late_ack ) const;
ConditionalOverlayCell( uint64_t s_exp, int s_col, uint64_t s_tentative )
: ConditionalOverlay( s_exp, s_col, s_tentative ),
replacement( 0 ),
unknown( false ),
original_contents()
: ConditionalOverlay( s_exp, s_col, s_tentative ), replacement( 0 ), unknown( false ), original_contents()
{}
void reset( void ) { unknown = false; original_contents.clear(); ConditionalOverlay::reset(); }
void reset_with_orig( void ) {
if ( (!active) || unknown ) {
void reset( void )
{
unknown = false;
original_contents.clear();
ConditionalOverlay::reset();
}
void reset_with_orig( void )
{
if ( ( !active ) || unknown ) {
reset();
return;
}
@@ -118,23 +129,25 @@ namespace Overlay {
original_contents.push_back( replacement );
ConditionalOverlay::reset();
}
};
};
class ConditionalOverlayRow {
public:
class ConditionalOverlayRow
{
public:
int row_num;
using overlay_cells_type = std::vector<ConditionalOverlayCell>;
overlay_cells_type overlay_cells;
void apply( Framebuffer &fb, uint64_t confirmed_epoch, bool flag ) const;
void apply( Framebuffer& fb, uint64_t confirmed_epoch, bool flag ) const;
ConditionalOverlayRow( int s_row_num ) : row_num( s_row_num ), overlay_cells() {}
};
};
/* the various overlays */
class NotificationEngine {
private:
/* the various overlays */
class NotificationEngine
{
private:
uint64_t last_word_from_server;
uint64_t last_acked_state;
std::string escape_key_string;
@@ -143,19 +156,21 @@ namespace Overlay {
uint64_t message_expiration;
bool show_quit_keystroke;
bool server_late( uint64_t ts ) const { return (ts - last_word_from_server) > 6500; }
bool reply_late( uint64_t ts ) const { return (ts - last_acked_state) > 10000; }
bool server_late( uint64_t ts ) const { return ( ts - last_word_from_server ) > 6500; }
bool reply_late( uint64_t ts ) const { return ( ts - last_acked_state ) > 10000; }
bool need_countup( uint64_t ts ) const { return server_late( ts ) || reply_late( ts ); }
public:
public:
void adjust_message( void );
void apply( Framebuffer &fb ) const;
const std::wstring &get_notification_string( void ) const { return message; }
void apply( Framebuffer& fb ) const;
const std::wstring& get_notification_string( void ) const { return message; }
void server_heard( uint64_t s_last_word ) { last_word_from_server = s_last_word; }
void server_acked( uint64_t s_last_acked ) { last_acked_state = s_last_acked; }
int wait_time( void ) const;
void set_notification_string( const std::wstring &s_message, bool permanent = false, bool s_show_quit_keystroke = true )
void set_notification_string( const std::wstring& s_message,
bool permanent = false,
bool s_show_quit_keystroke = true )
{
message = s_message;
if ( permanent ) {
@@ -167,16 +182,16 @@ namespace Overlay {
show_quit_keystroke = s_show_quit_keystroke;
}
void set_escape_key_string( const std::string &s_name )
void set_escape_key_string( const std::string& s_name )
{
char tmp[ 128 ];
char tmp[128];
snprintf( tmp, sizeof tmp, " [To quit: %s .]", s_name.c_str() );
escape_key_string = tmp;
}
void set_network_error( const std::string &s )
void set_network_error( const std::string& s )
{
wchar_t tmp[ 128 ];
wchar_t tmp[128];
swprintf( tmp, 128, L"%s", s.c_str() );
message = tmp;
@@ -192,10 +207,11 @@ namespace Overlay {
}
NotificationEngine();
};
};
class PredictionEngine {
private:
class PredictionEngine
{
private:
static const uint64_t SRTT_TRIGGER_LOW = 20; /* <= ms cures SRTT trigger to show predictions */
static const uint64_t SRTT_TRIGGER_HIGH = 30; /* > ms starts SRTT trigger */
@@ -221,56 +237,62 @@ namespace Overlay {
uint64_t local_frame_sent, local_frame_acked, local_frame_late_acked;
ConditionalOverlayRow & get_or_make_row( int row_num, int num_cols );
ConditionalOverlayRow& get_or_make_row( int row_num, int num_cols );
uint64_t prediction_epoch;
uint64_t confirmed_epoch;
void become_tentative( void );
void newline_carriage_return( const Framebuffer &fb );
void newline_carriage_return( const Framebuffer& fb );
bool flagging; /* whether we are underlining predictions */
bool srtt_trigger; /* show predictions because of slow round trip time */
unsigned int glitch_trigger; /* show predictions temporarily because of long-pending prediction */
uint64_t last_quick_confirmation;
ConditionalCursorMove & cursor( void ) { assert( !cursors.empty() ); return cursors.back(); }
ConditionalCursorMove& cursor( void )
{
assert( !cursors.empty() );
return cursors.back();
}
void kill_epoch( uint64_t epoch, const Framebuffer &fb );
void kill_epoch( uint64_t epoch, const Framebuffer& fb );
void init_cursor( const Framebuffer &fb );
void init_cursor( const Framebuffer& fb );
unsigned int send_interval;
int last_height, last_width;
public:
enum DisplayPreference {
public:
enum DisplayPreference
{
Always,
Never,
Adaptive,
Experimental
};
private:
private:
DisplayPreference display_preference;
bool predict_overwrite;
bool active( void ) const;
bool timing_tests_necessary( void ) const {
bool timing_tests_necessary( void ) const
{
/* Are there any timing-based triggers that haven't fired yet? */
return !( glitch_trigger && flagging );
}
public:
public:
void set_display_preference( DisplayPreference s_pref ) { display_preference = s_pref; }
void set_predict_overwrite( bool overwrite ) { predict_overwrite = overwrite; }
void apply( Framebuffer &fb ) const;
void new_user_byte( char the_byte, const Framebuffer &fb );
void cull( const Framebuffer &fb );
void apply( Framebuffer& fb ) const;
void new_user_byte( char the_byte, const Framebuffer& fb );
void cull( const Framebuffer& fb );
void reset( void );
@@ -280,61 +302,47 @@ namespace Overlay {
void set_send_interval( unsigned int x ) { send_interval = x; }
int wait_time( void ) const
{
return ( timing_tests_necessary() && active() )
? 50
: INT_MAX;
}
int wait_time( void ) const { return ( timing_tests_necessary() && active() ) ? 50 : INT_MAX; }
PredictionEngine( void ) : last_byte( 0 ), parser(), overlays(), cursors(),
local_frame_sent( 0 ), local_frame_acked( 0 ),
local_frame_late_acked( 0 ),
prediction_epoch( 1 ), confirmed_epoch( 0 ),
flagging( false ),
srtt_trigger( false ),
glitch_trigger( 0 ),
last_quick_confirmation( 0 ),
send_interval( 250 ),
last_height( 0 ), last_width( 0 ),
display_preference( Adaptive ),
predict_overwrite( false )
{
}
};
PredictionEngine( void )
: last_byte( 0 ), parser(), overlays(), cursors(), local_frame_sent( 0 ), local_frame_acked( 0 ),
local_frame_late_acked( 0 ), prediction_epoch( 1 ), confirmed_epoch( 0 ), flagging( false ),
srtt_trigger( false ), glitch_trigger( 0 ), last_quick_confirmation( 0 ), send_interval( 250 ),
last_height( 0 ), last_width( 0 ), display_preference( Adaptive ), predict_overwrite( false )
{}
};
class TitleEngine {
private:
class TitleEngine
{
private:
Terminal::Framebuffer::title_type prefix;
public:
void apply( Framebuffer &fb ) const { fb.prefix_window_title( prefix ); }
public:
void apply( Framebuffer& fb ) const { fb.prefix_window_title( prefix ); }
TitleEngine() : prefix() {}
void set_prefix( const std::wstring &s );
};
void set_prefix( const std::wstring& s );
};
/* the overlay manager */
class OverlayManager {
private:
/* the overlay manager */
class OverlayManager
{
private:
NotificationEngine notifications;
PredictionEngine predictions;
TitleEngine title;
public:
void apply( Framebuffer &fb );
public:
void apply( Framebuffer& fb );
NotificationEngine & get_notification_engine( void ) { return notifications; }
PredictionEngine & get_prediction_engine( void ) { return predictions; }
NotificationEngine& get_notification_engine( void ) { return notifications; }
PredictionEngine& get_prediction_engine( void ) { return predictions; }
void set_title_prefix( const std::wstring &s ) { title.set_prefix( s ); }
void set_title_prefix( const std::wstring& s ) { title.set_prefix( s ); }
OverlayManager() : notifications(), predictions(), title() {}
int wait_time( void ) const
{
return std::min( notifications.wait_time(), predictions.wait_time() );
}
};
int wait_time( void ) const { return std::min( notifications.wait_time(), predictions.wait_time() ); }
};
}
#endif
+9 -8
View File
@@ -1,17 +1,18 @@
#include <cstddef>
#include <cstdint>
#include "src/terminal/parser.h"
#include "src/statesync/completeterminal.h"
#include "src/terminal/parser.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
Terminal::Display display(false);
Terminal::Complete complete(80, 24);
Terminal::Framebuffer state(80, 24);
for (size_t i = 0; i < size; i++) {
complete.act(Parser::UserByte(data[i]));
extern "C" int LLVMFuzzerTestOneInput( const uint8_t* data, size_t size )
{
Terminal::Display display( false );
Terminal::Complete complete( 80, 24 );
Terminal::Framebuffer state( 80, 24 );
for ( size_t i = 0; i < size; i++ ) {
complete.act( Parser::UserByte( data[i] ) );
}
display.new_frame(true, state, complete.get_fb());
display.new_frame( true, state, complete.get_fb() );
return 0;
}
+4 -3
View File
@@ -3,12 +3,13 @@
#include "src/terminal/parser.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
extern "C" int LLVMFuzzerTestOneInput( const uint8_t* data, size_t size )
{
Parser::UTF8Parser parser;
Parser::Actions result;
for (size_t i = 0; i < size; i++) {
parser.input(data[i], result);
for ( size_t i = 0; i < size; i++ ) {
parser.input( data[i], result );
}
return 0;
+9 -11
View File
@@ -37,26 +37,24 @@
using namespace Network;
std::string Compressor::compress_str( const std::string &input )
std::string Compressor::compress_str( const std::string& input )
{
long unsigned int len = BUFFER_SIZE;
dos_assert( Z_OK == compress( buffer, &len,
reinterpret_cast<const unsigned char *>( input.data() ),
input.size() ) );
return std::string( reinterpret_cast<char *>( buffer ), len );
dos_assert( Z_OK
== compress( buffer, &len, reinterpret_cast<const unsigned char*>( input.data() ), input.size() ) );
return std::string( reinterpret_cast<char*>( buffer ), len );
}
std::string Compressor::uncompress_str( const std::string &input )
std::string Compressor::uncompress_str( const std::string& input )
{
long unsigned int len = BUFFER_SIZE;
dos_assert( Z_OK == uncompress( buffer, &len,
reinterpret_cast<const unsigned char *>( input.data() ),
input.size() ) );
return std::string( reinterpret_cast<char *>( buffer ), len );
dos_assert( Z_OK
== uncompress( buffer, &len, reinterpret_cast<const unsigned char*>( input.data() ), input.size() ) );
return std::string( reinterpret_cast<char*>( buffer ), len );
}
/* construct on first use */
Compressor & Network::get_compressor( void )
Compressor& Network::get_compressor( void )
{
static Compressor the_compressor;
return the_compressor;
+10 -9
View File
@@ -36,25 +36,26 @@
#include <string>
namespace Network {
class Compressor {
private:
class Compressor
{
private:
static const int BUFFER_SIZE = 2048 * 2048; /* effective limit on terminal size */
unsigned char buffer[BUFFER_SIZE];
public:
public:
Compressor() : buffer() {}
~Compressor() {}
std::string compress_str( const std::string &input );
std::string uncompress_str( const std::string &input );
std::string compress_str( const std::string& input );
std::string uncompress_str( const std::string& input );
/* unused */
Compressor( const Compressor & );
Compressor & operator=( const Compressor & );
};
Compressor( const Compressor& );
Compressor& operator=( const Compressor& );
};
Compressor & get_compressor( void );
Compressor& get_compressor( void );
}
#endif
+111 -145
View File
@@ -36,8 +36,8 @@
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
@@ -45,11 +45,11 @@
#include <netinet/in.h>
#include <unistd.h>
#include "src/crypto/byteorder.h"
#include "src/crypto/crypto.h"
#include "src/network/network.h"
#include "src/util/dos_assert.h"
#include "src/util/fatal_assert.h"
#include "src/crypto/byteorder.h"
#include "src/network/network.h"
#include "src/crypto/crypto.h"
#include "src/util/timestamp.h"
@@ -64,22 +64,20 @@
using namespace Network;
using namespace Crypto;
const uint64_t DIRECTION_MASK = uint64_t(1) << 63;
const uint64_t SEQUENCE_MASK = uint64_t(-1) ^ DIRECTION_MASK;
const uint64_t DIRECTION_MASK = uint64_t( 1 ) << 63;
const uint64_t SEQUENCE_MASK = uint64_t( -1 ) ^ DIRECTION_MASK;
/* Read in packet */
Packet::Packet( const Message & message )
Packet::Packet( const Message& message )
: seq( message.nonce.val() & SEQUENCE_MASK ),
direction( (message.nonce.val() & DIRECTION_MASK) ? TO_CLIENT : TO_SERVER ),
timestamp( -1 ),
timestamp_reply( -1 ),
payload()
direction( ( message.nonce.val() & DIRECTION_MASK ) ? TO_CLIENT : TO_SERVER ), timestamp( -1 ),
timestamp_reply( -1 ), payload()
{
dos_assert( message.text.size() >= 2 * sizeof( uint16_t ) );
const uint16_t *data = (uint16_t *)message.text.data();
timestamp = be16toh( data[ 0 ] );
timestamp_reply = be16toh( data[ 1 ] );
const uint16_t* data = (uint16_t*)message.text.data();
timestamp = be16toh( data[0] );
timestamp_reply = be16toh( data[1] );
payload = std::string( message.text.begin() + 2 * sizeof( uint16_t ), message.text.end() );
}
@@ -87,17 +85,17 @@ Packet::Packet( const Message & message )
/* Output from packet */
Message Packet::toMessage( void )
{
uint64_t direction_seq = (uint64_t( direction == TO_CLIENT ) << 63) | (seq & SEQUENCE_MASK);
uint64_t direction_seq = ( uint64_t( direction == TO_CLIENT ) << 63 ) | ( seq & SEQUENCE_MASK );
uint16_t ts_net[ 2 ] = { static_cast<uint16_t>( htobe16( timestamp ) ),
static_cast<uint16_t>( htobe16( timestamp_reply ) ) };
uint16_t ts_net[2]
= { static_cast<uint16_t>( htobe16( timestamp ) ), static_cast<uint16_t>( htobe16( timestamp_reply ) ) };
std::string timestamps = std::string( (char *)ts_net, 2 * sizeof( uint16_t ) );
std::string timestamps = std::string( (char*)ts_net, 2 * sizeof( uint16_t ) );
return Message( Nonce( direction_seq ), timestamps + payload );
}
Packet Connection::new_packet( const std::string &s_payload )
Packet Connection::new_packet( const std::string& s_payload )
{
uint16_t outgoing_timestamp_reply = -1;
@@ -105,7 +103,7 @@ Packet Connection::new_packet( const std::string &s_payload )
if ( now - saved_timestamp_received_at < 1000 ) { /* we have a recent received timestamp */
/* send "corrected" timestamp advanced by how long we held it */
outgoing_timestamp_reply = saved_timestamp + (now - saved_timestamp_received_at);
outgoing_timestamp_reply = saved_timestamp + ( now - saved_timestamp_received_at );
saved_timestamp = -1;
saved_timestamp_received_at = 0;
}
@@ -149,8 +147,7 @@ void Connection::prune_sockets( void )
}
}
Connection::Socket::Socket( int family )
: _fd( socket( family, SOCK_DGRAM, 0 ) )
Connection::Socket::Socket( int family ) : _fd( socket( family, SOCK_DGRAM, 0 ) )
{
if ( _fd < 0 ) {
throw NetworkException( "socket", errno );
@@ -185,13 +182,11 @@ void Connection::setup( void )
last_port_choice = timestamp();
}
const std::vector< int > Connection::fds( void ) const
const std::vector<int> Connection::fds( void ) const
{
std::vector< int > ret;
std::vector<int> ret;
for ( std::deque< Socket >::const_iterator it = socks.begin();
it != socks.end();
it++ ) {
for ( std::deque<Socket>::const_iterator it = socks.begin(); it != socks.end(); it++ ) {
ret.push_back( it->fd() );
}
@@ -212,43 +207,31 @@ void Connection::set_MTU( int family )
}
}
class AddrInfo {
class AddrInfo
{
public:
struct addrinfo *res;
AddrInfo( const char *node, const char *service,
const struct addrinfo *hints ) :
res( NULL ) {
struct addrinfo* res;
AddrInfo( const char* node, const char* service, const struct addrinfo* hints ) : res( NULL )
{
int errcode = getaddrinfo( node, service, hints, &res );
if ( errcode != 0 ) {
throw NetworkException( std::string( "Bad IP address (" ) + (node != NULL ? node : "(null)") + "): " + gai_strerror( errcode ), 0 );
throw NetworkException( std::string( "Bad IP address (" ) + ( node != NULL ? node : "(null)" )
+ "): " + gai_strerror( errcode ),
0 );
}
}
~AddrInfo() { freeaddrinfo(res); }
~AddrInfo() { freeaddrinfo( res ); }
private:
AddrInfo(const AddrInfo &);
AddrInfo &operator=(const AddrInfo &);
AddrInfo( const AddrInfo& );
AddrInfo& operator=( const AddrInfo& );
};
Connection::Connection( const char *desired_ip, const char *desired_port ) /* server */
: socks(),
has_remote_addr( false ),
remote_addr(),
remote_addr_len( 0 ),
server( true ),
MTU( DEFAULT_SEND_MTU ),
key(),
session( key ),
direction( TO_CLIENT ),
saved_timestamp( -1 ),
saved_timestamp_received_at( 0 ),
expected_receiver_seq( 0 ),
last_heard( -1 ),
last_port_choice( -1 ),
last_roundtrip_success( -1 ),
RTT_hit( false ),
SRTT( 1000 ),
RTTVAR( 500 ),
send_error()
Connection::Connection( const char* desired_ip, const char* desired_port ) /* server */
: socks(), has_remote_addr( false ), remote_addr(), remote_addr_len( 0 ), server( true ), MTU( DEFAULT_SEND_MTU ),
key(), session( key ), direction( TO_CLIENT ), saved_timestamp( -1 ), saved_timestamp_received_at( 0 ),
expected_receiver_seq( 0 ), last_heard( -1 ), last_port_choice( -1 ), last_roundtrip_success( -1 ),
RTT_hit( false ), SRTT( 1000 ), RTTVAR( 500 ), send_error()
{
setup();
@@ -263,33 +246,34 @@ Connection::Connection( const char *desired_ip, const char *desired_port ) /* se
int desired_port_high = -1;
if ( desired_port && !parse_portrange( desired_port, desired_port_low, desired_port_high ) ) {
throw NetworkException("Invalid port range", 0);
throw NetworkException( "Invalid port range", 0 );
}
/* try to bind to desired IP first */
if ( desired_ip ) {
try {
if ( try_bind( desired_ip, desired_port_low, desired_port_high ) ) { return; }
} catch ( const NetworkException &e ) {
fprintf( stderr, "Error binding to IP %s: %s\n",
desired_ip,
e.what() );
if ( try_bind( desired_ip, desired_port_low, desired_port_high ) ) {
return;
}
} catch ( const NetworkException& e ) {
fprintf( stderr, "Error binding to IP %s: %s\n", desired_ip, e.what() );
}
}
/* now try any local interface */
try {
if ( try_bind( NULL, desired_port_low, desired_port_high ) ) { return; }
} catch ( const NetworkException &e ) {
fprintf( stderr, "Error binding to any interface: %s\n",
e.what() );
if ( try_bind( NULL, desired_port_low, desired_port_high ) ) {
return;
}
} catch ( const NetworkException& e ) {
fprintf( stderr, "Error binding to any interface: %s\n", e.what() );
throw; /* this time it's fatal */
}
throw NetworkException( "Could not bind", errno );
}
bool Connection::try_bind( const char *addr, int port_low, int port_high )
bool Connection::try_bind( const char* addr, int port_low, int port_high )
{
struct addrinfo hints;
memset( &hints, 0, sizeof( hints ) );
@@ -313,7 +297,7 @@ bool Connection::try_bind( const char *addr, int port_low, int port_high )
socks.push_back( Socket( local_addr.sa.sa_family ) );
for ( int i = search_low; i <= search_high; i++ ) {
switch (local_addr.sa.sa_family) {
switch ( local_addr.sa.sa_family ) {
case AF_INET:
local_addr.sin.sin_port = htons( i );
break;
@@ -325,9 +309,9 @@ bool Connection::try_bind( const char *addr, int port_low, int port_high )
}
if ( local_addr.sa.sa_family == AF_INET6
&& memcmp(&local_addr.sin6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 ) {
&& memcmp( &local_addr.sin6.sin6_addr, &in6addr_any, sizeof( in6addr_any ) ) == 0 ) {
const int off = 0;
if ( setsockopt( sock(), IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off) ) ) {
if ( setsockopt( sock(), IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof( off ) ) ) {
perror( "setsockopt( IPV6_V6ONLY, off )" );
}
}
@@ -339,38 +323,26 @@ bool Connection::try_bind( const char *addr, int port_low, int port_high )
}
int saved_errno = errno;
socks.pop_back();
char host[ NI_MAXHOST ], serv[ NI_MAXSERV ];
int errcode = getnameinfo( &local_addr.sa, local_addr_len,
host, sizeof( host ), serv, sizeof( serv ),
char host[NI_MAXHOST], serv[NI_MAXSERV];
int errcode = getnameinfo( &local_addr.sa,
local_addr_len,
host,
sizeof( host ),
serv,
sizeof( serv ),
NI_DGRAM | NI_NUMERICHOST | NI_NUMERICSERV );
if ( errcode != 0 ) {
throw NetworkException( std::string( "bind: getnameinfo: " ) + gai_strerror( errcode ), 0 );
}
fprintf( stderr, "Failed binding to %s:%s\n",
host, serv );
fprintf( stderr, "Failed binding to %s:%s\n", host, serv );
throw NetworkException( "bind", saved_errno );
}
Connection::Connection( const char *key_str, const char *ip, const char *port ) /* client */
: socks(),
has_remote_addr( false ),
remote_addr(),
remote_addr_len( 0 ),
server( false ),
MTU( DEFAULT_SEND_MTU ),
key( key_str ),
session( key ),
direction( TO_SERVER ),
saved_timestamp( -1 ),
saved_timestamp_received_at( 0 ),
expected_receiver_seq( 0 ),
last_heard( -1 ),
last_port_choice( -1 ),
last_roundtrip_success( -1 ),
RTT_hit( false ),
SRTT( 1000 ),
RTTVAR( 500 ),
send_error()
Connection::Connection( const char* key_str, const char* ip, const char* port ) /* client */
: socks(), has_remote_addr( false ), remote_addr(), remote_addr_len( 0 ), server( false ),
MTU( DEFAULT_SEND_MTU ), key( key_str ), session( key ), direction( TO_SERVER ), saved_timestamp( -1 ),
saved_timestamp_received_at( 0 ), expected_receiver_seq( 0 ), last_heard( -1 ), last_port_choice( -1 ),
last_roundtrip_success( -1 ), RTT_hit( false ), SRTT( 1000 ), RTTVAR( 500 ), send_error()
{
setup();
@@ -392,7 +364,7 @@ Connection::Connection( const char *key_str, const char *ip, const char *port )
set_MTU( remote_addr.sa.sa_family );
}
void Connection::send( const std::string & s )
void Connection::send( const std::string& s )
{
if ( !has_remote_addr ) {
return;
@@ -402,8 +374,7 @@ void Connection::send( const std::string & s )
std::string p = session.encrypt( px.toMessage() );
ssize_t bytes_sent = sendto( sock(), p.data(), p.size(), MSG_DONTWAIT,
&remote_addr.sa, remote_addr_len );
ssize_t bytes_sent = sendto( sock(), p.data(), p.size(), MSG_DONTWAIT, &remote_addr.sa, remote_addr_len );
if ( bytes_sent != static_cast<ssize_t>( p.size() ) ) {
/* Make sendto() failure available to the frontend. */
@@ -422,8 +393,7 @@ void Connection::send( const std::string & s )
fprintf( stderr, "Server now detached from client.\n" );
}
} else { /* client */
if ( ( now - last_port_choice > PORT_HOP_INTERVAL )
&& ( now - last_roundtrip_success > PORT_HOP_INTERVAL ) ) {
if ( ( now - last_port_choice > PORT_HOP_INTERVAL ) && ( now - last_roundtrip_success > PORT_HOP_INTERVAL ) ) {
hop_port();
}
}
@@ -432,15 +402,12 @@ void Connection::send( const std::string & s )
std::string Connection::recv( void )
{
assert( !socks.empty() );
for ( std::deque< Socket >::const_iterator it = socks.begin();
it != socks.end();
it++ ) {
for ( std::deque<Socket>::const_iterator it = socks.begin(); it != socks.end(); it++ ) {
std::string payload;
try {
payload = recv_one( it->fd());
} catch ( NetworkException & e ) {
if ( (e.the_errno == EAGAIN)
|| (e.the_errno == EWOULDBLOCK) ) {
payload = recv_one( it->fd() );
} catch ( NetworkException& e ) {
if ( ( e.the_errno == EAGAIN ) || ( e.the_errno == EWOULDBLOCK ) ) {
continue;
} else {
throw;
@@ -461,8 +428,8 @@ std::string Connection::recv_one( int sock_to_recv )
struct msghdr header;
struct iovec msg_iovec;
char msg_payload[ Session::RECEIVE_MTU ];
char msg_control[ Session::RECEIVE_MTU ];
char msg_payload[Session::RECEIVE_MTU];
char msg_control[Session::RECEIVE_MTU];
/* receive source address */
header.msg_name = &packet_remote_addr;
@@ -494,32 +461,32 @@ std::string Connection::recv_one( int sock_to_recv )
/* receive ECN */
bool congestion_experienced = false;
struct cmsghdr *ecn_hdr = CMSG_FIRSTHDR( &header );
if ( ecn_hdr
&& ecn_hdr->cmsg_level == IPPROTO_IP
struct cmsghdr* ecn_hdr = CMSG_FIRSTHDR( &header );
if ( ecn_hdr && ecn_hdr->cmsg_level == IPPROTO_IP
&& ( ecn_hdr->cmsg_type == IP_TOS
#ifdef IP_RECVTOS
|| ecn_hdr->cmsg_type == IP_RECVTOS
#endif
) ) {
/* got one */
uint8_t *ecn_octet_p = (uint8_t *)CMSG_DATA( ecn_hdr );
uint8_t* ecn_octet_p = (uint8_t*)CMSG_DATA( ecn_hdr );
assert( ecn_octet_p );
congestion_experienced = (*ecn_octet_p & 0x03) == 0x03;
congestion_experienced = ( *ecn_octet_p & 0x03 ) == 0x03;
}
Packet p( session.decrypt( msg_payload, received_len ) );
dos_assert( p.direction == (server ? TO_SERVER : TO_CLIENT) ); /* prevent malicious playback to sender */
dos_assert( p.direction == ( server ? TO_SERVER : TO_CLIENT ) ); /* prevent malicious playback to sender */
if ( p.seq < expected_receiver_seq ) { /* don't use (but do return) out-of-order packets for timestamp or targeting */
if ( p.seq
< expected_receiver_seq ) { /* don't use (but do return) out-of-order packets for timestamp or targeting */
return p.payload;
}
expected_receiver_seq = p.seq + 1; /* this is security-sensitive because a replay attack could otherwise
screw up the timestamp and targeting */
if ( p.timestamp != uint16_t(-1) ) {
if ( p.timestamp != uint16_t( -1 ) ) {
saved_timestamp = p.timestamp;
saved_timestamp_received_at = timestamp();
@@ -533,7 +500,7 @@ std::string Connection::recv_one( int sock_to_recv )
}
}
if ( p.timestamp_reply != uint16_t(-1) ) {
if ( p.timestamp_reply != uint16_t( -1 ) ) {
uint16_t now = timestamp16();
double R = timestamp_diff( now, p.timestamp_reply );
@@ -546,8 +513,8 @@ std::string Connection::recv_one( int sock_to_recv )
const double alpha = 1.0 / 8.0;
const double beta = 1.0 / 4.0;
RTTVAR = (1 - beta) * RTTVAR + ( beta * fabs( SRTT - R ) );
SRTT = (1 - alpha) * SRTT + ( alpha * R );
RTTVAR = ( 1 - beta ) * RTTVAR + ( beta * fabs( SRTT - R ) );
SRTT = ( 1 - alpha ) * SRTT + ( alpha * R );
}
}
}
@@ -557,19 +524,22 @@ std::string Connection::recv_one( int sock_to_recv )
last_heard = timestamp();
if ( server && /* only client can roam */
( remote_addr_len != header.msg_namelen ||
memcmp( &remote_addr, &packet_remote_addr, remote_addr_len ) != 0 ) ) {
( remote_addr_len != header.msg_namelen
|| memcmp( &remote_addr, &packet_remote_addr, remote_addr_len ) != 0 ) ) {
remote_addr = packet_remote_addr;
remote_addr_len = header.msg_namelen;
char host[ NI_MAXHOST ], serv[ NI_MAXSERV ];
int errcode = getnameinfo( &remote_addr.sa, remote_addr_len,
host, sizeof( host ), serv, sizeof( serv ),
char host[NI_MAXHOST], serv[NI_MAXSERV];
int errcode = getnameinfo( &remote_addr.sa,
remote_addr_len,
host,
sizeof( host ),
serv,
sizeof( serv ),
NI_DGRAM | NI_NUMERICHOST | NI_NUMERICSERV );
if ( errcode != 0 ) {
throw NetworkException( std::string( "recv_one: getnameinfo: " ) + gai_strerror( errcode ), 0 );
}
fprintf( stderr, "Server now attached to client at %s:%s\n",
host, serv );
fprintf( stderr, "Server now attached to client at %s:%s\n", host, serv );
}
return p.payload;
}
@@ -583,10 +553,8 @@ std::string Connection::port( void ) const
throw NetworkException( "getsockname", errno );
}
char serv[ NI_MAXSERV ];
int errcode = getnameinfo( &local_addr.sa, addrlen,
NULL, 0, serv, sizeof( serv ),
NI_DGRAM | NI_NUMERICSERV );
char serv[NI_MAXSERV];
int errcode = getnameinfo( &local_addr.sa, addrlen, NULL, 0, serv, sizeof( serv ), NI_DGRAM | NI_NUMERICSERV );
if ( errcode != 0 ) {
throw NetworkException( std::string( "port: getnameinfo: " ) + gai_strerror( errcode ), 0 );
}
@@ -602,7 +570,7 @@ uint64_t Network::timestamp( void )
uint16_t Network::timestamp16( void )
{
uint16_t ts = timestamp() % 65536;
if ( ts == uint16_t(-1) ) {
if ( ts == uint16_t( -1 ) ) {
ts++;
}
return ts;
@@ -634,18 +602,17 @@ uint64_t Connection::timeout( void ) const
Connection::Socket::~Socket()
{
fatal_assert ( close( _fd ) == 0 );
fatal_assert( close( _fd ) == 0 );
}
Connection::Socket::Socket( const Socket & other )
: _fd( dup( other._fd ) )
Connection::Socket::Socket( const Socket& other ) : _fd( dup( other._fd ) )
{
if ( _fd < 0 ) {
throw NetworkException( "socket", errno );
}
}
Connection::Socket & Connection::Socket::operator=( const Socket & other )
Connection::Socket& Connection::Socket::operator=( const Socket& other )
{
if ( dup2( other._fd, _fd ) < 0 ) {
throw NetworkException( "socket", errno );
@@ -654,39 +621,39 @@ Connection::Socket & Connection::Socket::operator=( const Socket & other )
return *this;
}
bool Connection::parse_portrange( const char * desired_port, int & desired_port_low, int & desired_port_high )
bool Connection::parse_portrange( const char* desired_port, int& desired_port_low, int& desired_port_high )
{
/* parse "port" or "portlow:porthigh" */
desired_port_low = desired_port_high = 0;
char *end;
char* end;
long value;
/* parse first (only?) port */
errno = 0;
value = strtol( desired_port, &end, 10 );
if ( (errno != 0) || (*end != '\0' && *end != ':') ) {
if ( ( errno != 0 ) || ( *end != '\0' && *end != ':' ) ) {
fprintf( stderr, "Invalid (low) port number (%s)\n", desired_port );
return false;
}
if ( (value < 0) || (value > 65535) ) {
if ( ( value < 0 ) || ( value > 65535 ) ) {
fprintf( stderr, "(Low) port number %ld outside valid range [0..65535]\n", value );
return false;
}
desired_port_low = (int)value;
if (*end == '\0') { /* not a port range */
if ( *end == '\0' ) { /* not a port range */
desired_port_high = desired_port_low;
return true;
}
/* port range; parse high port */
const char * cp = end + 1;
const char* cp = end + 1;
errno = 0;
value = strtol( cp, &end, 10 );
if ( (errno != 0) || (*end != '\0') ) {
if ( ( errno != 0 ) || ( *end != '\0' ) ) {
fprintf( stderr, "Invalid high port number (%s)\n", cp );
return false;
}
if ( (value < 0) || (value > 65535) ) {
if ( ( value < 0 ) || ( value > 65535 ) ) {
fprintf( stderr, "High port number %ld outside valid range [0..65535]\n", value );
return false;
}
@@ -702,6 +669,5 @@ bool Connection::parse_portrange( const char * desired_port, int & desired_port_
return false;
}
return true;
}
+54 -48
View File
@@ -42,66 +42,71 @@
#include <string>
#include <vector>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "src/crypto/crypto.h"
using namespace Crypto;
namespace Network {
static const unsigned int MOSH_PROTOCOL_VERSION = 2; /* bumped for echo-ack */
static const unsigned int MOSH_PROTOCOL_VERSION = 2; /* bumped for echo-ack */
uint64_t timestamp( void );
uint16_t timestamp16( void );
uint16_t timestamp_diff( uint16_t tsnew, uint16_t tsold );
uint64_t timestamp( void );
uint16_t timestamp16( void );
uint16_t timestamp_diff( uint16_t tsnew, uint16_t tsold );
class NetworkException : public std::exception {
public:
class NetworkException : public std::exception
{
public:
std::string function;
int the_errno;
private:
std::string my_what;
public:
NetworkException( std::string s_function="<none>", int s_errno=0)
: function( s_function ), the_errno( s_errno ),
my_what(function + ": " + strerror(the_errno)) {}
const char *what() const throw () { return my_what.c_str(); }
~NetworkException() throw () {}
};
enum Direction {
private:
std::string my_what;
public:
NetworkException( std::string s_function = "<none>", int s_errno = 0 )
: function( s_function ), the_errno( s_errno ), my_what( function + ": " + strerror( the_errno ) )
{}
const char* what() const throw() { return my_what.c_str(); }
~NetworkException() throw() {}
};
enum Direction
{
TO_SERVER = 0,
TO_CLIENT = 1
};
};
class Packet {
public:
class Packet
{
public:
const uint64_t seq;
Direction direction;
uint16_t timestamp, timestamp_reply;
std::string payload;
Packet( Direction s_direction,
uint16_t s_timestamp, uint16_t s_timestamp_reply, const std::string & s_payload )
: seq( Crypto::unique() ), direction( s_direction ),
timestamp( s_timestamp ), timestamp_reply( s_timestamp_reply ), payload( s_payload )
Packet( Direction s_direction, uint16_t s_timestamp, uint16_t s_timestamp_reply, const std::string& s_payload )
: seq( Crypto::unique() ), direction( s_direction ), timestamp( s_timestamp ),
timestamp_reply( s_timestamp_reply ), payload( s_payload )
{}
Packet( const Message & message );
Packet( const Message& message );
Message toMessage( void );
};
};
union Addr {
union Addr {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr_storage ss;
};
};
class Connection {
private:
class Connection
{
private:
/*
* For IPv4, guess the typical (minimum) header length;
* fragmentation is not dangerous, just inefficient.
@@ -145,7 +150,7 @@ namespace Network {
static const int CONGESTION_TIMESTAMP_PENALTY = 500; /* ms */
bool try_bind( const char *addr, int port_low, int port_high );
bool try_bind( const char* addr, int port_low, int port_high );
class Socket
{
@@ -157,11 +162,11 @@ namespace Network {
Socket( int family );
~Socket();
Socket( const Socket & other );
Socket & operator=( const Socket & other );
Socket( const Socket& other );
Socket& operator=( const Socket& other );
};
std::deque< Socket > socks;
std::deque<Socket> socks;
bool has_remote_addr;
Addr remote_addr;
socklen_t remote_addr_len;
@@ -191,11 +196,15 @@ namespace Network {
/* Error from send()/sendto(). */
std::string send_error;
Packet new_packet( const std::string &s_payload );
Packet new_packet( const std::string& s_payload );
void hop_port( void );
int sock( void ) const { assert( !socks.empty() ); return socks.back().fd(); }
int sock( void ) const
{
assert( !socks.empty() );
return socks.back().fd();
}
void prune_sockets( void );
@@ -203,16 +212,16 @@ namespace Network {
void set_MTU( int family );
public:
public:
/* Network transport overhead. */
static const int ADDED_BYTES = 8 /* seqno/nonce */ + 4 /* timestamps */;
Connection( const char *desired_ip, const char *desired_port ); /* server */
Connection( const char *key_str, const char *ip, const char *port ); /* client */
Connection( const char* desired_ip, const char* desired_port ); /* server */
Connection( const char* key_str, const char* ip, const char* port ); /* client */
void send( const std::string & s );
void send( const std::string& s );
std::string recv( void );
const std::vector< int > fds( void ) const;
const std::vector<int> fds( void ) const;
int get_MTU( void ) const { return MTU; }
std::string port( void ) const;
@@ -222,18 +231,15 @@ namespace Network {
uint64_t timeout( void ) const;
double get_SRTT( void ) const { return SRTT; }
const Addr &get_remote_addr( void ) const { return remote_addr; }
const Addr& get_remote_addr( void ) const { return remote_addr; }
socklen_t get_remote_addr_len( void ) const { return remote_addr_len; }
std::string &get_send_error( void )
{
return send_error;
}
std::string& get_send_error( void ) { return send_error; }
void set_last_roundtrip_success( uint64_t s_success ) { last_roundtrip_success = s_success; }
static bool parse_portrange( const char * desired_port_range, int & desired_port_low, int & desired_port_high );
};
static bool parse_portrange( const char* desired_port_range, int& desired_port_low, int& desired_port_high );
};
}
#endif
+43 -35
View File
@@ -39,35 +39,32 @@
using namespace Network;
template <class MyState, class RemoteState>
Transport<MyState, RemoteState>::Transport( MyState &initial_state, RemoteState &initial_remote,
const char *desired_ip, const char *desired_port )
: connection( desired_ip, desired_port ),
sender( &connection, initial_state ),
template<class MyState, class RemoteState>
Transport<MyState, RemoteState>::Transport( MyState& initial_state,
RemoteState& initial_remote,
const char* desired_ip,
const char* desired_port )
: connection( desired_ip, desired_port ), sender( &connection, initial_state ),
received_states( 1, TimestampedState<RemoteState>( timestamp(), 0, initial_remote ) ),
receiver_quench_timer( 0 ),
last_receiver_state( initial_remote ),
fragments(),
verbose( 0 )
receiver_quench_timer( 0 ), last_receiver_state( initial_remote ), fragments(), verbose( 0 )
{
/* server */
}
template <class MyState, class RemoteState>
Transport<MyState, RemoteState>::Transport( MyState &initial_state, RemoteState &initial_remote,
const char *key_str, const char *ip, const char *port )
: connection( key_str, ip, port ),
sender( &connection, initial_state ),
template<class MyState, class RemoteState>
Transport<MyState, RemoteState>::Transport( MyState& initial_state,
RemoteState& initial_remote,
const char* key_str,
const char* ip,
const char* port )
: connection( key_str, ip, port ), sender( &connection, initial_state ),
received_states( 1, TimestampedState<RemoteState>( timestamp(), 0, initial_remote ) ),
receiver_quench_timer( 0 ),
last_receiver_state( initial_remote ),
fragments(),
verbose( 0 )
receiver_quench_timer( 0 ), last_receiver_state( initial_remote ), fragments(), verbose( 0 )
{
/* client */
}
template <class MyState, class RemoteState>
template<class MyState, class RemoteState>
void Transport<MyState, RemoteState>::recv( void )
{
std::string s( connection.recv() );
@@ -86,7 +83,7 @@ void Transport<MyState, RemoteState>::recv( void )
connection.set_last_roundtrip_success( sender.get_sent_state_acked_timestamp() );
/* first, make sure we don't already have the new state */
for ( typename std::list< TimestampedState<RemoteState> >::iterator i = received_states.begin();
for ( typename std::list<TimestampedState<RemoteState>>::iterator i = received_states.begin();
i != received_states.end();
i++ ) {
if ( inst.new_num() == i->num ) {
@@ -96,7 +93,7 @@ void Transport<MyState, RemoteState>::recv( void )
/* now, make sure we do have the old state */
bool found = 0;
typename std::list< TimestampedState<RemoteState> >::iterator reference_state = received_states.begin();
typename std::list<TimestampedState<RemoteState>>::iterator reference_state = received_states.begin();
while ( reference_state != received_states.end() ) {
if ( inst.old_num() == reference_state->num ) {
found = true;
@@ -106,7 +103,8 @@ void Transport<MyState, RemoteState>::recv( void )
}
if ( !found ) {
// fprintf( stderr, "Ignoring out-of-order packet. Reference state %d has been discarded or hasn't yet been received.\n", int(inst.old_num) );
// fprintf( stderr, "Ignoring out-of-order packet. Reference state %d has been discarded or hasn't yet been
// received.\n", int(inst.old_num) );
return; /* this is security-sensitive and part of how we enforce idempotency */
}
@@ -121,8 +119,11 @@ void Transport<MyState, RemoteState>::recv( void )
uint64_t now = timestamp();
if ( now < receiver_quench_timer ) { /* deny letting state grow further */
if ( verbose ) {
fprintf( stderr, "[%u] Receiver queue full, discarding %d (malicious sender or long-unidirectional connectivity?)\n",
(unsigned int)(timestamp() % 100000), (int)inst.new_num() );
fprintf(
stderr,
"[%u] Receiver queue full, discarding %d (malicious sender or long-unidirectional connectivity?)\n",
(unsigned int)( timestamp() % 100000 ),
(int)inst.new_num() );
}
return;
} else {
@@ -140,21 +141,28 @@ void Transport<MyState, RemoteState>::recv( void )
}
/* Insert new state in sorted place */
for ( typename std::list< TimestampedState<RemoteState> >::iterator i = received_states.begin();
for ( typename std::list<TimestampedState<RemoteState>>::iterator i = received_states.begin();
i != received_states.end();
i++ ) {
if ( i->num > new_state.num ) {
received_states.insert( i, new_state );
if ( verbose ) {
fprintf( stderr, "[%u] Received OUT-OF-ORDER state %d [ack %d]\n",
(unsigned int)(timestamp() % 100000), (int)new_state.num, (int)inst.ack_num() );
fprintf( stderr,
"[%u] Received OUT-OF-ORDER state %d [ack %d]\n",
(unsigned int)( timestamp() % 100000 ),
(int)new_state.num,
(int)inst.ack_num() );
}
return;
}
}
if ( verbose ) {
fprintf( stderr, "[%u] Received state %d [coming from %d, ack %d]\n",
(unsigned int)(timestamp() % 100000), (int)new_state.num, (int)inst.old_num(), (int)inst.ack_num() );
fprintf( stderr,
"[%u] Received state %d [coming from %d, ack %d]\n",
(unsigned int)( timestamp() % 100000 ),
(int)new_state.num,
(int)inst.old_num(),
(int)inst.ack_num() );
}
received_states.push_back( new_state );
sender.set_ack_num( received_states.back().num );
@@ -167,12 +175,12 @@ void Transport<MyState, RemoteState>::recv( void )
}
/* The sender uses throwaway_num to tell us the earliest received state that we need to keep around */
template <class MyState, class RemoteState>
template<class MyState, class RemoteState>
void Transport<MyState, RemoteState>::process_throwaway_until( uint64_t throwaway_num )
{
typename std::list< TimestampedState<RemoteState> >::iterator i = received_states.begin();
typename std::list<TimestampedState<RemoteState>>::iterator i = received_states.begin();
while ( i != received_states.end() ) {
typename std::list< TimestampedState<RemoteState> >::iterator inext = i;
typename std::list<TimestampedState<RemoteState>>::iterator inext = i;
inext++;
if ( i->num < throwaway_num ) {
received_states.erase( i );
@@ -183,16 +191,16 @@ void Transport<MyState, RemoteState>::process_throwaway_until( uint64_t throwawa
fatal_assert( received_states.size() > 0 );
}
template <class MyState, class RemoteState>
template<class MyState, class RemoteState>
std::string Transport<MyState, RemoteState>::get_remote_diff( void )
{
/* find diff between last receiver state and current remote state, then rationalize states */
std::string ret( received_states.back().state.diff_from( last_receiver_state ) );
const RemoteState *oldest_receiver_state = &received_states.front().state;
const RemoteState* oldest_receiver_state = &received_states.front().state;
for ( typename std::list< TimestampedState<RemoteState> >::reverse_iterator i = received_states.rbegin();
for ( typename std::list<TimestampedState<RemoteState>>::reverse_iterator i = received_states.rbegin();
i != received_states.rend();
i++ ) {
i->state.subtract( oldest_receiver_state );
+27 -18
View File
@@ -44,10 +44,10 @@
#include "transportfragment.h"
namespace Network {
template <class MyState, class RemoteState>
class Transport
{
private:
template<class MyState, class RemoteState>
class Transport
{
private:
/* the underlying, encrypted network connection */
Connection connection;
@@ -58,17 +58,22 @@ namespace Network {
void process_throwaway_until( uint64_t throwaway_num );
/* simple receiver */
std::list< TimestampedState<RemoteState> > received_states;
std::list<TimestampedState<RemoteState>> received_states;
uint64_t receiver_quench_timer;
RemoteState last_receiver_state; /* the state we were in when user last queried state */
FragmentAssembly fragments;
unsigned int verbose;
public:
Transport( MyState &initial_state, RemoteState &initial_remote,
const char *desired_ip, const char *desired_port );
Transport( MyState &initial_state, RemoteState &initial_remote,
const char *key_str, const char *ip, const char *port );
public:
Transport( MyState& initial_state,
RemoteState& initial_remote,
const char* desired_ip,
const char* desired_port );
Transport( MyState& initial_state,
RemoteState& initial_remote,
const char* key_str,
const char* ip,
const char* port );
/* Send data or an ack if necessary. */
void tick( void ) { sender.tick(); }
@@ -96,16 +101,20 @@ namespace Network {
std::string port( void ) const { return connection.port(); }
std::string get_key( void ) const { return connection.get_key(); }
MyState &get_current_state( void ) { return sender.get_current_state(); }
void set_current_state( const MyState &x ) { sender.set_current_state( x ); }
MyState& get_current_state( void ) { return sender.get_current_state(); }
void set_current_state( const MyState& x ) { sender.set_current_state( x ); }
uint64_t get_remote_state_num( void ) const { return received_states.back().num; }
const TimestampedState<RemoteState> & get_latest_remote_state( void ) const { return received_states.back(); }
const TimestampedState<RemoteState>& get_latest_remote_state( void ) const { return received_states.back(); }
const std::vector< int > fds( void ) const { return connection.fds(); }
const std::vector<int> fds( void ) const { return connection.fds(); }
void set_verbose( unsigned int s_verbose ) { sender.set_verbose( s_verbose ); verbose = s_verbose; }
void set_verbose( unsigned int s_verbose )
{
sender.set_verbose( s_verbose );
verbose = s_verbose;
}
void set_send_delay( int new_delay ) { sender.set_send_delay( new_delay ); }
@@ -115,11 +124,11 @@ namespace Network {
unsigned int send_interval( void ) const { return sender.send_interval(); }
const Addr &get_remote_addr( void ) const { return connection.get_remote_addr(); }
const Addr& get_remote_addr( void ) const { return connection.get_remote_addr(); }
socklen_t get_remote_addr_len( void ) const { return connection.get_remote_addr_len(); }
std::string &get_send_error( void ) { return connection.get_send_error(); }
};
std::string& get_send_error( void ) { return connection.get_send_error(); }
};
}
#endif
+21 -25
View File
@@ -32,11 +32,11 @@
#include <cassert>
#include "src/crypto/byteorder.h"
#include "transportfragment.h"
#include "src/protobufs/transportinstruction.pb.h"
#include "compressor.h"
#include "src/crypto/byteorder.h"
#include "src/protobufs/transportinstruction.pb.h"
#include "src/util/fatal_assert.h"
#include "transportfragment.h"
using namespace Network;
using namespace TransportBuffers;
@@ -44,13 +44,13 @@ using namespace TransportBuffers;
static std::string network_order_string( uint16_t host_order )
{
uint16_t net_int = htobe16( host_order );
return std::string( (char *)&net_int, sizeof( net_int ) );
return std::string( (char*)&net_int, sizeof( net_int ) );
}
static std::string network_order_string( uint64_t host_order )
{
uint64_t net_int = htobe64( host_order );
return std::string( (char *)&net_int, sizeof( net_int ) );
return std::string( (char*)&net_int, sizeof( net_int ) );
}
std::string Fragment::tostring( void )
@@ -61,7 +61,8 @@ std::string Fragment::tostring( void )
ret += network_order_string( id );
fatal_assert( !( fragment_num & 0x8000 ) ); /* effective limit on size of a terminal screen change or buffered user input */
fatal_assert(
!( fragment_num & 0x8000 ) ); /* effective limit on size of a terminal screen change or buffered user input */
uint16_t combined_fragment_num = ( final << 15 ) | fragment_num;
ret += network_order_string( combined_fragment_num );
@@ -72,23 +73,22 @@ std::string Fragment::tostring( void )
return ret;
}
Fragment::Fragment( const std::string &x )
: id( -1 ), fragment_num( -1 ), final( false ), initialized( true ),
contents()
Fragment::Fragment( const std::string& x )
: id( -1 ), fragment_num( -1 ), final( false ), initialized( true ), contents()
{
fatal_assert( x.size() >= frag_header_len );
contents = std::string( x.begin() + frag_header_len, x.end() );
uint64_t data64;
uint16_t *data16 = (uint16_t *)x.data();
uint16_t* data16 = (uint16_t*)x.data();
memcpy( &data64, x.data(), sizeof( data64 ) );
id = be64toh( data64 );
fragment_num = be16toh( data16[ 4 ] );
fragment_num = be16toh( data16[4] );
final = ( fragment_num & 0x8000 ) >> 15;
fragment_num &= 0x7FFF;
}
bool FragmentAssembly::add_fragment( Fragment &frag )
bool FragmentAssembly::add_fragment( Fragment& frag )
{
/* see if this is a totally new packet */
if ( current_id != frag.id ) {
@@ -100,8 +100,7 @@ bool FragmentAssembly::add_fragment( Fragment &frag )
current_id = frag.id;
} else { /* not a new packet */
/* see if we already have this fragment */
if ( (fragments.size() > frag.fragment_num)
&& (fragments.at( frag.fragment_num ).initialized) ) {
if ( ( fragments.size() > frag.fragment_num ) && ( fragments.at( frag.fragment_num ).initialized ) ) {
/* make sure new version is same as what we already have */
assert( fragments.at( frag.fragment_num ) == frag );
} else {
@@ -148,27 +147,24 @@ Instruction FragmentAssembly::get_assembly( void )
return ret;
}
bool Fragment::operator==( const Fragment &x ) const
bool Fragment::operator==( const Fragment& x ) const
{
return ( id == x.id ) && ( fragment_num == x.fragment_num ) && ( final == x.final )
&& ( initialized == x.initialized ) && ( contents == x.contents );
}
std::vector<Fragment> Fragmenter::make_fragments( const Instruction &inst, size_t MTU )
std::vector<Fragment> Fragmenter::make_fragments( const Instruction& inst, size_t MTU )
{
MTU -= Fragment::frag_header_len;
if ( (inst.old_num() != last_instruction.old_num())
|| (inst.new_num() != last_instruction.new_num())
|| (inst.ack_num() != last_instruction.ack_num())
|| (inst.throwaway_num() != last_instruction.throwaway_num())
|| (inst.chaff() != last_instruction.chaff())
|| (inst.protocol_version() != last_instruction.protocol_version())
|| (last_MTU != MTU) ) {
if ( ( inst.old_num() != last_instruction.old_num() ) || ( inst.new_num() != last_instruction.new_num() )
|| ( inst.ack_num() != last_instruction.ack_num() )
|| ( inst.throwaway_num() != last_instruction.throwaway_num() )
|| ( inst.chaff() != last_instruction.chaff() )
|| ( inst.protocol_version() != last_instruction.protocol_version() ) || ( last_MTU != MTU ) ) {
next_instruction_id++;
}
if ( (inst.old_num() == last_instruction.old_num())
&& (inst.new_num() == last_instruction.new_num()) ) {
if ( ( inst.old_num() == last_instruction.old_num() ) && ( inst.new_num() == last_instruction.new_num() ) ) {
assert( inst.diff() == last_instruction.diff() );
}
+23 -26
View File
@@ -40,11 +40,11 @@
#include "src/protobufs/transportinstruction.pb.h"
namespace Network {
using namespace TransportBuffers;
using namespace TransportBuffers;
class Fragment
{
public:
class Fragment
{
public:
static const size_t frag_header_len = sizeof( uint64_t ) + sizeof( uint16_t );
uint64_t id;
@@ -55,51 +55,48 @@ namespace Network {
std::string contents;
Fragment()
: id( -1 ), fragment_num( -1 ), final( false ), initialized( false ), contents()
Fragment() : id( -1 ), fragment_num( -1 ), final( false ), initialized( false ), contents() {}
Fragment( uint64_t s_id, uint16_t s_fragment_num, bool s_final, const std::string& s_contents )
: id( s_id ), fragment_num( s_fragment_num ), final( s_final ), initialized( true ), contents( s_contents )
{}
Fragment( uint64_t s_id, uint16_t s_fragment_num, bool s_final, const std::string & s_contents )
: id( s_id ), fragment_num( s_fragment_num ), final( s_final ), initialized( true ),
contents( s_contents )
{}
Fragment( const std::string &x );
Fragment( const std::string& x );
std::string tostring( void );
bool operator==( const Fragment &x ) const;
};
bool operator==( const Fragment& x ) const;
};
class FragmentAssembly
{
private:
class FragmentAssembly
{
private:
std::vector<Fragment> fragments;
uint64_t current_id;
int fragments_arrived, fragments_total;
public:
public:
FragmentAssembly() : fragments(), current_id( -1 ), fragments_arrived( 0 ), fragments_total( -1 ) {}
bool add_fragment( Fragment &inst );
bool add_fragment( Fragment& inst );
Instruction get_assembly( void );
};
};
class Fragmenter
{
private:
class Fragmenter
{
private:
uint64_t next_instruction_id;
Instruction last_instruction;
size_t last_MTU;
public:
public:
Fragmenter() : next_instruction_id( 0 ), last_instruction(), last_MTU( -1 )
{
last_instruction.set_old_num( -1 );
last_instruction.set_new_num( -1 );
}
std::vector<Fragment> make_fragments( const Instruction &inst, size_t MTU );
std::vector<Fragment> make_fragments( const Instruction& inst, size_t MTU );
uint64_t last_ack_sent( void ) const { return last_instruction.ack_num(); }
};
};
}
+67 -77
View File
@@ -46,30 +46,18 @@
using namespace Network;
template <class MyState>
TransportSender<MyState>::TransportSender( Connection *s_connection, MyState &initial_state )
: connection( s_connection ),
current_state( initial_state ),
template<class MyState>
TransportSender<MyState>::TransportSender( Connection* s_connection, MyState& initial_state )
: connection( s_connection ), current_state( initial_state ),
sent_states( 1, TimestampedState<MyState>( timestamp(), 0, initial_state ) ),
assumed_receiver_state( sent_states.begin() ),
fragmenter(),
next_ack_time( timestamp() ),
next_send_time( timestamp() ),
verbose( 0 ),
shutdown_in_progress( false ),
shutdown_tries( 0 ),
shutdown_start( -1 ),
ack_num( 0 ),
pending_data_ack( false ),
SEND_MINDELAY( 8 ),
last_heard( 0 ),
prng(),
assumed_receiver_state( sent_states.begin() ), fragmenter(), next_ack_time( timestamp() ),
next_send_time( timestamp() ), verbose( 0 ), shutdown_in_progress( false ), shutdown_tries( 0 ),
shutdown_start( -1 ), ack_num( 0 ), pending_data_ack( false ), SEND_MINDELAY( 8 ), last_heard( 0 ), prng(),
mindelay_clock( -1 )
{
}
{}
/* Try to send roughly two frames per RTT, bounded by limits on frame rate */
template <class MyState>
template<class MyState>
unsigned int TransportSender<MyState>::send_interval( void ) const
{
int SEND_INTERVAL = lrint( ceil( connection->get_SRTT() / 2.0 ) );
@@ -83,7 +71,7 @@ unsigned int TransportSender<MyState>::send_interval( void ) const
}
/* Housekeeping routine to calculate next send and ack times */
template <class MyState>
template<class MyState>
void TransportSender<MyState>::calculate_timers( void )
{
uint64_t now = timestamp();
@@ -94,38 +82,35 @@ void TransportSender<MyState>::calculate_timers( void )
/* Cut out common prefix of all states */
rationalize_states();
if ( pending_data_ack && (next_ack_time > now + ACK_DELAY) ) {
if ( pending_data_ack && ( next_ack_time > now + ACK_DELAY ) ) {
next_ack_time = now + ACK_DELAY;
}
if ( !(current_state == sent_states.back().state) ) {
if ( !( current_state == sent_states.back().state ) ) {
if ( mindelay_clock == uint64_t( -1 ) ) {
mindelay_clock = now;
}
next_send_time = std::max( mindelay_clock + SEND_MINDELAY,
sent_states.back().timestamp + send_interval() );
} else if ( !(current_state == assumed_receiver_state->state)
&& (last_heard + ACTIVE_RETRY_TIMEOUT > now) ) {
next_send_time = std::max( mindelay_clock + SEND_MINDELAY, sent_states.back().timestamp + send_interval() );
} else if ( !( current_state == assumed_receiver_state->state ) && ( last_heard + ACTIVE_RETRY_TIMEOUT > now ) ) {
next_send_time = sent_states.back().timestamp + send_interval();
if ( mindelay_clock != uint64_t( -1 ) ) {
next_send_time = std::max( next_send_time, mindelay_clock + SEND_MINDELAY );
}
} else if ( !(current_state == sent_states.front().state )
&& (last_heard + ACTIVE_RETRY_TIMEOUT > now) ) {
} else if ( !( current_state == sent_states.front().state ) && ( last_heard + ACTIVE_RETRY_TIMEOUT > now ) ) {
next_send_time = sent_states.back().timestamp + connection->timeout() + ACK_DELAY;
} else {
next_send_time = uint64_t(-1);
next_send_time = uint64_t( -1 );
}
/* speed up shutdown sequence */
if ( shutdown_in_progress || (ack_num == uint64_t(-1)) ) {
if ( shutdown_in_progress || ( ack_num == uint64_t( -1 ) ) ) {
next_ack_time = sent_states.back().timestamp + send_interval();
}
}
/* How many ms to wait until next event */
template <class MyState>
template<class MyState>
int TransportSender<MyState>::wait_time( void )
{
calculate_timers();
@@ -149,7 +134,7 @@ int TransportSender<MyState>::wait_time( void )
}
/* Send data or an empty ack if necessary */
template <class MyState>
template<class MyState>
void TransportSender<MyState>::tick( void )
{
calculate_timers(); /* updates assumed receiver state and rationalizes */
@@ -160,8 +145,7 @@ void TransportSender<MyState>::tick( void )
uint64_t now = timestamp();
if ( (now < next_ack_time)
&& (now < next_send_time) ) {
if ( ( now < next_ack_time ) && ( now < next_send_time ) ) {
return;
}
@@ -187,22 +171,22 @@ void TransportSender<MyState>::tick( void )
}
if ( diff.empty() ) {
if ( (now >= next_ack_time) ) {
if ( ( now >= next_ack_time ) ) {
send_empty_ack();
mindelay_clock = uint64_t( -1 );
}
if ( (now >= next_send_time) ) {
if ( ( now >= next_send_time ) ) {
next_send_time = uint64_t( -1 );
mindelay_clock = uint64_t( -1 );
}
} else if ( (now >= next_send_time) || (now >= next_ack_time) ) {
} else if ( ( now >= next_send_time ) || ( now >= next_ack_time ) ) {
/* Send diffs or ack */
send_to_receiver( diff );
mindelay_clock = uint64_t( -1 );
}
}
template <class MyState>
template<class MyState>
void TransportSender<MyState>::send_empty_ack( void )
{
uint64_t now = timestamp();
@@ -221,22 +205,24 @@ void TransportSender<MyState>::send_empty_ack( void )
send_in_fragments( "", new_num );
next_ack_time = now + ACK_INTERVAL;
next_send_time = uint64_t(-1);
next_send_time = uint64_t( -1 );
}
template <class MyState>
void TransportSender<MyState>::add_sent_state( uint64_t the_timestamp, uint64_t num, MyState &state )
template<class MyState>
void TransportSender<MyState>::add_sent_state( uint64_t the_timestamp, uint64_t num, MyState& state )
{
sent_states.push_back( TimestampedState<MyState>( the_timestamp, num, state ) );
if ( sent_states.size() > 32 ) { /* limit on state queue */
typename sent_states_type::iterator last = sent_states.end();
for ( int i = 0; i < 16; i++ ) { last--; }
for ( int i = 0; i < 16; i++ ) {
last--;
}
sent_states.erase( last ); /* erase state from middle of queue */
}
}
template <class MyState>
void TransportSender<MyState>::send_to_receiver( const std::string & diff )
template<class MyState>
void TransportSender<MyState>::send_to_receiver( const std::string& diff )
{
uint64_t new_num;
if ( current_state == sent_states.back().state ) { /* previously sent */
@@ -263,10 +249,10 @@ void TransportSender<MyState>::send_to_receiver( const std::string & diff )
assumed_receiver_state = sent_states.end();
assumed_receiver_state--;
next_ack_time = timestamp() + ACK_INTERVAL;
next_send_time = uint64_t(-1);
next_send_time = uint64_t( -1 );
}
template <class MyState>
template<class MyState>
void TransportSender<MyState>::update_assumed_receiver_state( void )
{
uint64_t now = timestamp();
@@ -275,13 +261,13 @@ void TransportSender<MyState>::update_assumed_receiver_state( void )
transmitted recently enough ago */
assumed_receiver_state = sent_states.begin();
typename std::list< TimestampedState<MyState> >::iterator i = sent_states.begin();
typename std::list<TimestampedState<MyState>>::iterator i = sent_states.begin();
i++;
while ( i != sent_states.end() ) {
assert( now >= i->timestamp );
if ( uint64_t(now - i->timestamp) < connection->timeout() + ACK_DELAY ) {
if ( uint64_t( now - i->timestamp ) < connection->timeout() + ACK_DELAY ) {
assumed_receiver_state = i;
} else {
return;
@@ -291,33 +277,33 @@ void TransportSender<MyState>::update_assumed_receiver_state( void )
}
}
template <class MyState>
template<class MyState>
void TransportSender<MyState>::rationalize_states( void )
{
const MyState * known_receiver_state = &sent_states.front().state;
const MyState* known_receiver_state = &sent_states.front().state;
current_state.subtract( known_receiver_state );
for ( typename std::list< TimestampedState<MyState> >::reverse_iterator i = sent_states.rbegin();
for ( typename std::list<TimestampedState<MyState>>::reverse_iterator i = sent_states.rbegin();
i != sent_states.rend();
i++ ) {
i->state.subtract( known_receiver_state );
}
}
template <class MyState>
template<class MyState>
const std::string TransportSender<MyState>::make_chaff( void )
{
const size_t CHAFF_MAX = 16;
const size_t chaff_len = prng.uint8() % (CHAFF_MAX + 1);
const size_t chaff_len = prng.uint8() % ( CHAFF_MAX + 1 );
char chaff[ CHAFF_MAX ];
char chaff[CHAFF_MAX];
prng.fill( chaff, chaff_len );
return std::string( chaff, chaff_len );
}
template <class MyState>
void TransportSender<MyState>::send_in_fragments( const std::string & diff, uint64_t new_num )
template<class MyState>
void TransportSender<MyState>::send_in_fragments( const std::string& diff, uint64_t new_num )
{
Instruction inst;
@@ -329,32 +315,37 @@ void TransportSender<MyState>::send_in_fragments( const std::string & diff, uint
inst.set_diff( diff );
inst.set_chaff( make_chaff() );
if ( new_num == uint64_t(-1) ) {
if ( new_num == uint64_t( -1 ) ) {
shutdown_tries++;
}
std::vector<Fragment> fragments = fragmenter.make_fragments( inst, connection->get_MTU()
- Network::Connection::ADDED_BYTES
- Crypto::Session::ADDED_BYTES );
for ( std::vector<Fragment>::iterator i = fragments.begin();
i != fragments.end();
i++ ) {
std::vector<Fragment> fragments = fragmenter.make_fragments(
inst, connection->get_MTU() - Network::Connection::ADDED_BYTES - Crypto::Session::ADDED_BYTES );
for ( std::vector<Fragment>::iterator i = fragments.begin(); i != fragments.end(); i++ ) {
connection->send( i->tostring() );
if ( verbose ) {
fprintf( stderr, "[%u] Sent [%d=>%d] id %d, frag %d ack=%d, throwaway=%d, len=%d, frame rate=%.2f, timeout=%d, srtt=%.1f\n",
(unsigned int)(timestamp() % 100000), (int)inst.old_num(), (int)inst.new_num(), (int)i->id, (int)i->fragment_num,
(int)inst.ack_num(), (int)inst.throwaway_num(), (int)i->contents.size(),
fprintf(
stderr,
"[%u] Sent [%d=>%d] id %d, frag %d ack=%d, throwaway=%d, len=%d, frame rate=%.2f, timeout=%d, srtt=%.1f\n",
(unsigned int)( timestamp() % 100000 ),
(int)inst.old_num(),
(int)inst.new_num(),
(int)i->id,
(int)i->fragment_num,
(int)inst.ack_num(),
(int)inst.throwaway_num(),
(int)i->contents.size(),
1000.0 / (double)send_interval(),
(int)connection->timeout(), connection->get_SRTT() );
(int)connection->timeout(),
connection->get_SRTT() );
}
}
pending_data_ack = false;
}
template <class MyState>
template<class MyState>
void TransportSender<MyState>::process_acknowledgment_through( uint64_t ack_num )
{
/* Ignore ack if we have culled the state it's acknowledging */
@@ -380,7 +371,7 @@ void TransportSender<MyState>::process_acknowledgment_through( uint64_t ack_num
}
/* give up on getting acknowledgement for shutdown */
template <class MyState>
template<class MyState>
bool TransportSender<MyState>::shutdown_ack_timed_out( void ) const
{
if ( shutdown_in_progress ) {
@@ -395,7 +386,7 @@ bool TransportSender<MyState>::shutdown_ack_timed_out( void ) const
}
/* Executed upon entry to new receiver state */
template <class MyState>
template<class MyState>
void TransportSender<MyState>::set_ack_num( uint64_t s_ack_num )
{
ack_num = s_ack_num;
@@ -403,8 +394,8 @@ void TransportSender<MyState>::set_ack_num( uint64_t s_ack_num )
/* Investigate diff against known receiver state instead */
/* Mutates proposed_diff */
template <class MyState>
void TransportSender<MyState>::attempt_prospective_resend_optimization( std::string &proposed_diff )
template<class MyState>
void TransportSender<MyState>::attempt_prospective_resend_optimization( std::string& proposed_diff )
{
if ( assumed_receiver_state == sent_states.begin() ) {
return;
@@ -416,9 +407,8 @@ void TransportSender<MyState>::attempt_prospective_resend_optimization( std::str
or if it would lengthen it by no more than 100 bytes and still be
less than 1000 bytes. */
if ( (resend_diff.size() <= proposed_diff.size())
|| ( (resend_diff.size() < 1000)
&& (resend_diff.size() - proposed_diff.size() < 100) ) ) {
if ( ( resend_diff.size() <= proposed_diff.size() )
|| ( ( resend_diff.size() < 1000 ) && ( resend_diff.size() - proposed_diff.size() < 100 ) ) ) {
assumed_receiver_state = sent_states.begin();
proposed_diff = resend_diff;
}
+40 -31
View File
@@ -30,45 +30,44 @@
also delete it here.
*/
#ifndef TRANSPORT_SENDER_HPP
#define TRANSPORT_SENDER_HPP
#include <string>
#include <list>
#include <string>
#include "src/crypto/prng.h"
#include "src/network/network.h"
#include "src/protobufs/transportinstruction.pb.h"
#include "transportstate.h"
#include "transportfragment.h"
#include "src/crypto/prng.h"
#include "transportstate.h"
namespace Network {
using namespace TransportBuffers;
using namespace TransportBuffers;
/* timing parameters */
const int SEND_INTERVAL_MIN = 20; /* ms between frames */
const int SEND_INTERVAL_MAX = 250; /* ms between frames */
const int ACK_INTERVAL = 3000; /* ms between empty acks */
const int ACK_DELAY = 100; /* ms before delayed ack */
const int SHUTDOWN_RETRIES = 16; /* number of shutdown packets to send before giving up */
const int ACTIVE_RETRY_TIMEOUT = 10000; /* attempt to resend at frame rate */
/* timing parameters */
const int SEND_INTERVAL_MIN = 20; /* ms between frames */
const int SEND_INTERVAL_MAX = 250; /* ms between frames */
const int ACK_INTERVAL = 3000; /* ms between empty acks */
const int ACK_DELAY = 100; /* ms before delayed ack */
const int SHUTDOWN_RETRIES = 16; /* number of shutdown packets to send before giving up */
const int ACTIVE_RETRY_TIMEOUT = 10000; /* attempt to resend at frame rate */
template <class MyState>
class TransportSender
{
private:
template<class MyState>
class TransportSender
{
private:
/* helper methods for tick() */
void update_assumed_receiver_state( void );
void attempt_prospective_resend_optimization( std::string &proposed_diff );
void attempt_prospective_resend_optimization( std::string& proposed_diff );
void rationalize_states( void );
void send_to_receiver( const std::string & diff );
void send_to_receiver( const std::string& diff );
void send_empty_ack( void );
void send_in_fragments( const std::string & diff, uint64_t new_num );
void add_sent_state( uint64_t the_timestamp, uint64_t num, MyState &state );
void send_in_fragments( const std::string& diff, uint64_t new_num );
void add_sent_state( uint64_t the_timestamp, uint64_t num, MyState& state );
/* state of sender */
Connection *connection;
Connection* connection;
MyState current_state;
@@ -108,9 +107,9 @@ namespace Network {
uint64_t mindelay_clock; /* time of first pending change to current state */
public:
public:
/* constructor */
TransportSender( Connection *s_connection, MyState &initial_state );
TransportSender( Connection* s_connection, MyState& initial_state );
/* Send data or an ack if necessary */
void tick( void );
@@ -131,12 +130,22 @@ namespace Network {
void remote_heard( uint64_t ts ) { last_heard = ts; }
/* Starts shutdown sequence */
void start_shutdown( void ) { if ( !shutdown_in_progress ) { shutdown_start = timestamp(); shutdown_in_progress = true; } }
void start_shutdown( void )
{
if ( !shutdown_in_progress ) {
shutdown_start = timestamp();
shutdown_in_progress = true;
}
}
/* Misc. getters and setters */
/* Cannot modify current_state while shutdown in progress */
MyState &get_current_state( void ) { assert( !shutdown_in_progress ); return current_state; }
void set_current_state( const MyState &x )
MyState& get_current_state( void )
{
assert( !shutdown_in_progress );
return current_state;
}
void set_current_state( const MyState& x )
{
assert( !shutdown_in_progress );
current_state = x;
@@ -145,8 +154,8 @@ namespace Network {
void set_verbose( unsigned int s_verbose ) { verbose = s_verbose; }
bool get_shutdown_in_progress( void ) const { return shutdown_in_progress; }
bool get_shutdown_acknowledged( void ) const { return sent_states.front().num == uint64_t(-1); }
bool get_counterparty_shutdown_acknowledged( void ) const { return fragmenter.last_ack_sent() == uint64_t(-1); }
bool get_shutdown_acknowledged( void ) const { return sent_states.front().num == uint64_t( -1 ); }
bool get_counterparty_shutdown_acknowledged( void ) const { return fragmenter.last_ack_sent() == uint64_t( -1 ); }
uint64_t get_sent_state_acked_timestamp( void ) const { return sent_states.front().timestamp; }
uint64_t get_sent_state_acked( void ) const { return sent_states.front().num; }
uint64_t get_sent_state_last( void ) const { return sent_states.back().num; }
@@ -158,9 +167,9 @@ namespace Network {
unsigned int send_interval( void ) const;
/* nonexistent methods to satisfy -Weffc++ */
TransportSender( const TransportSender &x );
TransportSender & operator=( const TransportSender &x );
};
TransportSender( const TransportSender& x );
TransportSender& operator=( const TransportSender& x );
};
}
#endif
+6 -6
View File
@@ -34,18 +34,18 @@
#define TRANSPORT_STATE_HPP
namespace Network {
template <class State>
class TimestampedState
{
public:
template<class State>
class TimestampedState
{
public:
uint64_t timestamp;
uint64_t num;
State state;
TimestampedState( uint64_t s_timestamp, uint64_t s_num, const State &s_state )
TimestampedState( uint64_t s_timestamp, uint64_t s_num, const State& s_state )
: timestamp( s_timestamp ), num( s_num ), state( s_state )
{}
};
};
}
#endif
+29 -31
View File
@@ -41,17 +41,15 @@ using namespace Parser;
using namespace Terminal;
using namespace HostBuffers;
string Complete::act( const string &str )
string Complete::act( const string& str )
{
for ( unsigned int i = 0; i < str.size(); i++ ) {
/* parse octet into up to three actions */
parser.input( str[ i ], actions );
parser.input( str[i], actions );
/* apply actions to terminal and delete them */
for ( Actions::iterator it = actions.begin();
it != actions.end();
it++ ) {
Action &act = **it;
for ( Actions::iterator it = actions.begin(); it != actions.end(); it++ ) {
Action& act = **it;
act.act_on_terminal( &terminal );
}
actions.clear();
@@ -60,7 +58,7 @@ string Complete::act( const string &str )
return terminal.read_octets_to_host();
}
string Complete::act( const Action &act )
string Complete::act( const Action& act )
{
/* apply action to terminal */
act.act_on_terminal( &terminal );
@@ -68,26 +66,26 @@ string Complete::act( const Action &act )
}
/* interface for Network::Transport */
string Complete::diff_from( const Complete &existing ) const
string Complete::diff_from( const Complete& existing ) const
{
HostBuffers::HostMessage output;
if ( existing.get_echo_ack() != get_echo_ack() ) {
assert( get_echo_ack() >= existing.get_echo_ack() );
Instruction *new_echo = output.add_instruction();
Instruction* new_echo = output.add_instruction();
new_echo->MutableExtension( echoack )->set_echo_ack_num( get_echo_ack() );
}
if ( !(existing.get_fb() == get_fb()) ) {
if ( (existing.get_fb().ds.get_width() != terminal.get_fb().ds.get_width())
|| (existing.get_fb().ds.get_height() != terminal.get_fb().ds.get_height()) ) {
Instruction *new_res = output.add_instruction();
if ( !( existing.get_fb() == get_fb() ) ) {
if ( ( existing.get_fb().ds.get_width() != terminal.get_fb().ds.get_width() )
|| ( existing.get_fb().ds.get_height() != terminal.get_fb().ds.get_height() ) ) {
Instruction* new_res = output.add_instruction();
new_res->MutableExtension( resize )->set_width( terminal.get_fb().ds.get_width() );
new_res->MutableExtension( resize )->set_height( terminal.get_fb().ds.get_height() );
}
string update = display.new_frame( true, existing.get_fb(), terminal.get_fb() );
if ( !update.empty() ) {
Instruction *new_inst = output.add_instruction();
Instruction* new_inst = output.add_instruction();
new_inst->MutableExtension( hostbytes )->set_hoststring( update );
}
}
@@ -97,10 +95,10 @@ string Complete::diff_from( const Complete &existing ) const
string Complete::init_diff( void ) const
{
return diff_from( Complete( get_fb().ds.get_width(), get_fb().ds.get_height() ));
return diff_from( Complete( get_fb().ds.get_width(), get_fb().ds.get_height() ) );
}
void Complete::apply_string( const string & diff )
void Complete::apply_string( const string& diff )
{
HostBuffers::HostMessage input;
fatal_assert( input.ParseFromString( diff ) );
@@ -120,10 +118,10 @@ void Complete::apply_string( const string & diff )
}
}
bool Complete::operator==( Complete const &x ) const
bool Complete::operator==( Complete const& x ) const
{
// assert( parser == x.parser ); /* parser state is irrelevant for us */
return (terminal == x.terminal) && (echo_ack == x.echo_ack);
return ( terminal == x.terminal ) && ( echo_ack == x.echo_ack );
}
bool Complete::set_echo_ack( uint64_t now )
@@ -131,16 +129,13 @@ bool Complete::set_echo_ack( uint64_t now )
bool ret = false;
uint64_t newest_echo_ack = 0;
for ( input_history_type::const_iterator i = input_history.begin();
i != input_history.end();
i++ ) {
for ( input_history_type::const_iterator i = input_history.begin(); i != input_history.end(); i++ ) {
if ( i->second <= now - ECHO_TIMEOUT ) {
newest_echo_ack = i->first;
}
}
for ( input_history_type::iterator i = input_history.begin();
i != input_history.end(); ) {
for ( input_history_type::iterator i = input_history.begin(); i != input_history.end(); ) {
input_history_type::iterator i_next = i;
i_next++;
if ( i->first < newest_echo_ack ) {
@@ -179,11 +174,11 @@ int Complete::wait_time( uint64_t now ) const
return next_echo_ack_time - now;
}
bool Complete::compare( const Complete &other ) const
bool Complete::compare( const Complete& other ) const
{
bool ret = false;
const Framebuffer &fb = terminal.get_fb();
const Framebuffer &other_fb = other.terminal.get_fb();
const Framebuffer& fb = terminal.get_fb();
const Framebuffer& other_fb = other.terminal.get_fb();
const int height = fb.ds.get_height();
const int other_height = other_fb.ds.get_height();
const int width = fb.ds.get_width();
@@ -203,11 +198,14 @@ bool Complete::compare( const Complete &other ) const
}
}
if ( (fb.ds.get_cursor_row() != other_fb.ds.get_cursor_row())
|| (fb.ds.get_cursor_col() != other_fb.ds.get_cursor_col()) ) {
fprintf( stderr, "Cursor mismatch: (%d, %d) vs. (%d, %d).\n",
fb.ds.get_cursor_row(), fb.ds.get_cursor_col(),
other_fb.ds.get_cursor_row(), other_fb.ds.get_cursor_col() );
if ( ( fb.ds.get_cursor_row() != other_fb.ds.get_cursor_row() )
|| ( fb.ds.get_cursor_col() != other_fb.ds.get_cursor_col() ) ) {
fprintf( stderr,
"Cursor mismatch: (%d, %d) vs. (%d, %d).\n",
fb.ds.get_cursor_row(),
fb.ds.get_cursor_col(),
other_fb.ds.get_cursor_row(),
other_fb.ds.get_cursor_col() );
ret = true;
}
/* XXX should compare other terminal state too (mouse mode, bell. etc.) */
+16 -14
View File
@@ -42,8 +42,9 @@
/* This class represents the complete terminal -- a UTF8Parser feeding Actions to an Emulator. */
namespace Terminal {
class Complete {
private:
class Complete
{
private:
Parser::UTF8Parser parser;
Terminal::Emulator terminal;
Terminal::Display display;
@@ -59,14 +60,15 @@ namespace Terminal {
static const int ECHO_TIMEOUT = 50; /* for late ack */
public:
Complete( size_t width, size_t height ) : parser(), terminal( width, height ), display( false ),
actions(), input_history(), echo_ack( 0 ) {}
public:
Complete( size_t width, size_t height )
: parser(), terminal( width, height ), display( false ), actions(), input_history(), echo_ack( 0 )
{}
std::string act( const std::string &str );
std::string act( const Parser::Action &act );
std::string act( const std::string& str );
std::string act( const Parser::Action& act );
const Framebuffer & get_fb( void ) const { return terminal.get_fb(); }
const Framebuffer& get_fb( void ) const { return terminal.get_fb(); }
void reset_input( void ) { parser.reset_input(); }
uint64_t get_echo_ack( void ) const { return echo_ack; }
bool set_echo_ack( uint64_t now );
@@ -74,14 +76,14 @@ namespace Terminal {
int wait_time( uint64_t now ) const;
/* interface for Network::Transport */
void subtract( const Complete * ) const {}
std::string diff_from( const Complete &existing ) const;
void subtract( const Complete* ) const {}
std::string diff_from( const Complete& existing ) const;
std::string init_diff( void ) const;
void apply_string( const std::string & diff );
bool operator==( const Complete &x ) const;
void apply_string( const std::string& diff );
bool operator==( const Complete& x ) const;
bool compare( const Complete &other ) const;
};
bool compare( const Complete& other ) const;
};
}
#endif
+22 -27
View File
@@ -33,24 +33,22 @@
#include <cassert>
#include <typeinfo>
#include "src/protobufs/userinput.pb.h"
#include "src/statesync/user.h"
#include "src/util/fatal_assert.h"
#include "src/protobufs/userinput.pb.h"
using namespace Parser;
using namespace Network;
using namespace ClientBuffers;
void UserStream::subtract( const UserStream *prefix )
void UserStream::subtract( const UserStream* prefix )
{
// if we are subtracting ourself from ourself, just clear the std::deque
if ( this == prefix ) {
actions.clear();
return;
}
for ( std::deque<UserEvent>::const_iterator i = prefix->actions.begin();
i != prefix->actions.end();
i++ ) {
for ( std::deque<UserEvent>::const_iterator i = prefix->actions.begin(); i != prefix->actions.end(); i++ ) {
assert( this != prefix );
assert( !actions.empty() );
assert( *i == actions.front() );
@@ -58,13 +56,11 @@ void UserStream::subtract( const UserStream *prefix )
}
}
std::string UserStream::diff_from( const UserStream &existing ) const
std::string UserStream::diff_from( const UserStream& existing ) const
{
std::deque<UserEvent>::const_iterator my_it = actions.begin();
for ( std::deque<UserEvent>::const_iterator i = existing.actions.begin();
i != existing.actions.end();
i++ ) {
for ( std::deque<UserEvent>::const_iterator i = existing.actions.begin(); i != existing.actions.end(); i++ ) {
assert( my_it != actions.end() );
assert( *i == *my_it );
my_it++;
@@ -74,26 +70,25 @@ std::string UserStream::diff_from( const UserStream &existing ) const
while ( my_it != actions.end() ) {
switch ( my_it->type ) {
case UserByteType:
{
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( std::string( &the_byte, 1 ) );
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( std::string( &the_byte, 1 ) );
} else {
Instruction *new_inst = output.add_instruction();
Instruction* new_inst = output.add_instruction();
new_inst->MutableExtension( keystroke )->set_keys( &the_byte, 1 );
}
}
break;
case ResizeType:
{
Instruction *new_inst = output.add_instruction();
} 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;
} break;
default:
assert( !"unexpected event type" );
break;
@@ -105,7 +100,7 @@ std::string UserStream::diff_from( const UserStream &existing ) const
return output.SerializeAsString();
}
void UserStream::apply_string( const std::string &diff )
void UserStream::apply_string( const std::string& diff )
{
ClientBuffers::UserMessage input;
fatal_assert( input.ParseFromString( diff ) );
@@ -123,13 +118,13 @@ void UserStream::apply_string( const std::string &diff )
}
}
const Parser::Action &UserStream::get_action( unsigned int i ) const
const Parser::Action& UserStream::get_action( unsigned int i ) const
{
switch( actions[ i ].type ) {
switch ( actions[i].type ) {
case UserByteType:
return actions[ i ].userbyte;
return actions[i].userbyte;
case ResizeType:
return actions[ i ].resize;
return actions[i].resize;
default:
assert( !"unexpected action type" );
static const Parser::Ignore nothing = Parser::Ignore();
+29 -24
View File
@@ -41,52 +41,57 @@
#include "src/terminal/parseraction.h"
namespace Network {
enum UserEventType {
enum UserEventType
{
UserByteType = 0,
ResizeType = 1
};
};
class UserEvent
{
public:
class UserEvent
{
public:
UserEventType type;
Parser::UserByte userbyte;
Parser::Resize resize;
UserEvent( const Parser::UserByte & s_userbyte ) : type( UserByteType ), userbyte( s_userbyte ), resize( -1, -1 ) {}
UserEvent( const Parser::Resize & s_resize ) : type( ResizeType ), userbyte( 0 ), resize( s_resize ) {}
UserEvent( const Parser::UserByte& s_userbyte ) : type( UserByteType ), userbyte( s_userbyte ), resize( -1, -1 )
{}
UserEvent( const Parser::Resize& s_resize ) : type( ResizeType ), userbyte( 0 ), resize( s_resize ) {}
private:
private:
UserEvent();
public:
bool operator==( const UserEvent &x ) const { return ( type == x.type ) && ( userbyte == x.userbyte ) && ( resize == x.resize ); }
};
class UserStream
public:
bool operator==( const UserEvent& x ) const
{
private:
return ( type == x.type ) && ( userbyte == x.userbyte ) && ( resize == x.resize );
}
};
class UserStream
{
private:
std::deque<UserEvent> actions;
public:
public:
UserStream() : actions() {}
void push_back( const Parser::UserByte & s_userbyte ) { actions.push_back( UserEvent( s_userbyte ) ); }
void push_back( const Parser::Resize & s_resize ) { actions.push_back( UserEvent( s_resize ) ); }
void push_back( const Parser::UserByte& s_userbyte ) { actions.push_back( UserEvent( s_userbyte ) ); }
void push_back( const Parser::Resize& s_resize ) { actions.push_back( UserEvent( s_resize ) ); }
bool empty( void ) const { return actions.empty(); }
size_t size( void ) const { return actions.size(); }
const Parser::Action &get_action( unsigned int i ) const;
const Parser::Action& get_action( unsigned int i ) const;
/* interface for Network::Transport */
void subtract( const UserStream *prefix );
std::string diff_from( const UserStream &existing ) const;
void subtract( const UserStream* prefix );
std::string diff_from( const UserStream& existing ) const;
std::string init_diff( void ) const { return diff_from( UserStream() ); };
void apply_string( const std::string &diff );
bool operator==( const UserStream &x ) const { return actions == x.actions; }
void apply_string( const std::string& diff );
bool operator==( const UserStream& x ) const { return actions == x.actions; }
bool compare( const UserStream & ) { return false; }
};
bool compare( const UserStream& ) { return false; }
};
}
#endif
+16 -20
View File
@@ -40,8 +40,7 @@
const Parser::StateFamily Parser::family;
static void append_or_delete( Parser::ActionPointer act,
Parser::Actions &vec )
static void append_or_delete( Parser::ActionPointer act, Parser::Actions& vec )
{
assert( act );
@@ -50,7 +49,7 @@ static void append_or_delete( Parser::ActionPointer act,
}
}
void Parser::Parser::input( wchar_t ch, Actions &ret )
void Parser::Parser::input( wchar_t ch, Actions& ret )
{
Transition tx = state->input( ch );
@@ -66,24 +65,23 @@ void Parser::Parser::input( wchar_t ch, Actions &ret )
}
}
Parser::UTF8Parser::UTF8Parser()
: parser(), buf_len( 0 )
Parser::UTF8Parser::UTF8Parser() : parser(), buf_len( 0 )
{
assert( BUF_SIZE >= (size_t)MB_CUR_MAX );
buf[0] = '\0';
}
void Parser::UTF8Parser::input( char c, Actions &ret )
void Parser::UTF8Parser::input( char c, Actions& ret )
{
assert( buf_len < BUF_SIZE );
/* 1-byte UTF-8 character, aka ASCII? Cheat. */
if ( buf_len == 0 && static_cast<unsigned char>(c) <= 0x7f ) {
parser.input( static_cast<wchar_t>(c), ret );
if ( buf_len == 0 && static_cast<unsigned char>( c ) <= 0x7f ) {
parser.input( static_cast<wchar_t>( c ), ret );
return;
}
buf[ buf_len++ ] = c;
buf[buf_len++] = c;
/* This function will only work in a UTF-8 locale. */
wchar_t pwc;
@@ -108,19 +106,19 @@ void Parser::UTF8Parser::input( char c, Actions &ret )
buf_len = 0;
pwc = L'\0';
bytes_parsed = 1;
} else if ( bytes_parsed == (size_t) -1 ) {
} else if ( bytes_parsed == (size_t)-1 ) {
/* invalid sequence, use replacement character and try again with last char */
assert( errno == EILSEQ );
if ( buf_len > 1 ) {
buf[ 0 ] = buf[ buf_len - 1 ];
buf[0] = buf[buf_len - 1];
bytes_parsed = buf_len - 1;
buf_len = 1;
} else {
buf_len = 0;
bytes_parsed = 1;
}
pwc = (wchar_t) 0xFFFD;
} else if ( bytes_parsed == (size_t) -2 ) {
pwc = (wchar_t)0xFFFD;
} else if ( bytes_parsed == (size_t)-2 ) {
/* can't parse incomplete multibyte character */
total_bytes_parsed += buf_len;
continue;
@@ -137,16 +135,16 @@ void Parser::UTF8Parser::input( char c, Actions &ret )
const uint32_t pwcheck = pwc;
if ( pwcheck > 0x10FFFF ) { /* outside Unicode range */
pwc = (wchar_t) 0xFFFD;
pwc = (wchar_t)0xFFFD;
}
if ( (pwcheck >= 0xD800) && (pwcheck <= 0xDFFF) ) { /* surrogate code point */
if ( ( pwcheck >= 0xD800 ) && ( pwcheck <= 0xDFFF ) ) { /* surrogate code point */
/*
OS X unfortunately allows these sequences without EILSEQ, but
they are ill-formed UTF-8 and we shouldn't repeat them to the
user's terminal.
*/
pwc = (wchar_t) 0xFFFD;
pwc = (wchar_t)0xFFFD;
}
parser.input( pwc, ret );
@@ -155,11 +153,9 @@ void Parser::UTF8Parser::input( char c, Actions &ret )
}
}
Parser::Parser::Parser( const Parser &other )
: state( other.state )
{}
Parser::Parser::Parser( const Parser& other ) : state( other.state ) {}
Parser::Parser & Parser::Parser::operator=( const Parser &other )
Parser::Parser& Parser::Parser::operator=( const Parser& other )
{
state = other.state;
return *this;
+21 -23
View File
@@ -39,47 +39,45 @@
#include <cstring>
#include <cwchar>
#include "parsertransition.h"
#include "src/terminal/parseraction.h"
#include "parserstate.h"
#include "parserstatefamily.h"
#include "parsertransition.h"
#include "src/terminal/parseraction.h"
namespace Parser {
extern const StateFamily family;
extern const StateFamily family;
class Parser {
private:
State const *state;
class Parser
{
private:
State const* state;
public:
public:
Parser() : state( &family.s_Ground ) {}
Parser( const Parser &other );
Parser & operator=( const Parser & );
Parser( const Parser& other );
Parser& operator=( const Parser& );
~Parser() {}
void input( wchar_t ch, Actions &actions );
void input( wchar_t ch, Actions& actions );
void reset_input( void )
{
state = &family.s_Ground;
}
void reset_input( void ) { state = &family.s_Ground; }
};
};
static const size_t BUF_SIZE = 8;
static const size_t BUF_SIZE = 8;
class UTF8Parser {
private:
class UTF8Parser
{
private:
Parser parser;
char buf[ BUF_SIZE ];
char buf[BUF_SIZE];
size_t buf_len;
public:
public:
UTF8Parser();
void input( char c, Actions &actions );
void input( char c, Actions& actions );
void reset_input( void )
{
@@ -87,7 +85,7 @@ namespace Parser {
buf[0] = '\0';
buf_len = 0;
}
};
};
}
#endif
+13 -14
View File
@@ -38,63 +38,62 @@
using namespace Parser;
void Print::act_on_terminal( Terminal::Emulator *emu ) const
void Print::act_on_terminal( Terminal::Emulator* emu ) const
{
emu->print( this );
}
void Execute::act_on_terminal( Terminal::Emulator *emu ) const
void Execute::act_on_terminal( Terminal::Emulator* emu ) const
{
emu->execute( this );
}
void Clear::act_on_terminal( Terminal::Emulator *emu ) const
void Clear::act_on_terminal( Terminal::Emulator* emu ) const
{
emu->dispatch.clear( this );
}
void Param::act_on_terminal( Terminal::Emulator *emu ) const
void Param::act_on_terminal( Terminal::Emulator* emu ) const
{
emu->dispatch.newparamchar( this );
}
void Collect::act_on_terminal( Terminal::Emulator *emu ) const
void Collect::act_on_terminal( Terminal::Emulator* emu ) const
{
emu->dispatch.collect( this );
}
void CSI_Dispatch::act_on_terminal( Terminal::Emulator *emu ) const
void CSI_Dispatch::act_on_terminal( Terminal::Emulator* emu ) const
{
emu->CSI_dispatch( this );
}
void Esc_Dispatch::act_on_terminal( Terminal::Emulator *emu ) const
void Esc_Dispatch::act_on_terminal( Terminal::Emulator* emu ) const
{
emu->Esc_dispatch( this );
}
void OSC_Put::act_on_terminal( Terminal::Emulator *emu ) const
void OSC_Put::act_on_terminal( Terminal::Emulator* emu ) const
{
emu->dispatch.OSC_put( this );
}
void OSC_Start::act_on_terminal( Terminal::Emulator *emu ) const
void OSC_Start::act_on_terminal( Terminal::Emulator* emu ) const
{
emu->dispatch.OSC_start( this );
}
void OSC_End::act_on_terminal( Terminal::Emulator *emu ) const
void OSC_End::act_on_terminal( Terminal::Emulator* emu ) const
{
emu->OSC_end( this );
}
void UserByte::act_on_terminal( Terminal::Emulator *emu ) const
void UserByte::act_on_terminal( Terminal::Emulator* emu ) const
{
emu->dispatch.terminal_to_host.append( emu->user.input( this,
emu->fb.ds.application_mode_cursor_keys ) );
emu->dispatch.terminal_to_host.append( emu->user.input( this, emu->fb.ds.application_mode_cursor_keys ) );
}
void Resize::act_on_terminal( Terminal::Emulator *emu ) const
void Resize::act_on_terminal( Terminal::Emulator* emu ) const
{
emu->resize( width, height );
}
+90 -80
View File
@@ -38,128 +38,138 @@
#include <vector>
namespace Terminal {
class Emulator;
class Emulator;
}
namespace Parser {
class Action
{
public:
class Action
{
public:
wchar_t ch;
bool char_present;
virtual std::string name( void ) = 0;
virtual void act_on_terminal( Terminal::Emulator * ) const {};
virtual void act_on_terminal( Terminal::Emulator* ) const {};
virtual bool ignore() const { return false; }
Action() : ch( -1 ), char_present( false ) {};
virtual ~Action() {};
};
};
using ActionPointer = std::shared_ptr<Action>;
using Actions = std::vector<ActionPointer>;
using ActionPointer = std::shared_ptr<Action>;
using Actions = std::vector<ActionPointer>;
class Ignore : public Action {
public:
class Ignore : public Action
{
public:
std::string name( void ) { return std::string( "Ignore" ); }
bool ignore() const { return true; }
};
class Print : public Action {
public:
};
class Print : public Action
{
public:
std::string name( void ) { return std::string( "Print" ); }
void act_on_terminal( Terminal::Emulator *emu ) const;
};
class Execute : public Action {
public:
void act_on_terminal( Terminal::Emulator* emu ) const;
};
class Execute : public Action
{
public:
std::string name( void ) { return std::string( "Execute" ); }
void act_on_terminal( Terminal::Emulator *emu ) const;
};
class Clear : public Action {
public:
void act_on_terminal( Terminal::Emulator* emu ) const;
};
class Clear : public Action
{
public:
std::string name( void ) { return std::string( "Clear" ); }
void act_on_terminal( Terminal::Emulator *emu ) const;
};
class Collect : public Action {
public:
void act_on_terminal( Terminal::Emulator* emu ) const;
};
class Collect : public Action
{
public:
std::string name( void ) { return std::string( "Collect" ); }
void act_on_terminal( Terminal::Emulator *emu ) const;
};
class Param : public Action {
public:
void act_on_terminal( Terminal::Emulator* emu ) const;
};
class Param : public Action
{
public:
std::string name( void ) { return std::string( "Param" ); }
void act_on_terminal( Terminal::Emulator *emu ) const;
};
class Esc_Dispatch : public Action {
public:
void act_on_terminal( Terminal::Emulator* emu ) const;
};
class Esc_Dispatch : public Action
{
public:
std::string name( void ) { return std::string( "Esc_Dispatch" ); }
void act_on_terminal( Terminal::Emulator *emu ) const;
};
class CSI_Dispatch : public Action {
public:
void act_on_terminal( Terminal::Emulator* emu ) const;
};
class CSI_Dispatch : public Action
{
public:
std::string name( void ) { return std::string( "CSI_Dispatch" ); }
void act_on_terminal( Terminal::Emulator *emu ) const;
};
class Hook : public Action {
public: std::string name( void ) { return std::string( "Hook" ); }
};
class Put : public Action {
public: std::string name( void ) { return std::string( "Put" ); }
};
class Unhook : public Action {
public: std::string name( void ) { return std::string( "Unhook" ); }
};
class OSC_Start : public Action {
public:
void act_on_terminal( Terminal::Emulator* emu ) const;
};
class Hook : public Action
{
public:
std::string name( void ) { return std::string( "Hook" ); }
};
class Put : public Action
{
public:
std::string name( void ) { return std::string( "Put" ); }
};
class Unhook : public Action
{
public:
std::string name( void ) { return std::string( "Unhook" ); }
};
class OSC_Start : public Action
{
public:
std::string name( void ) { return std::string( "OSC_Start" ); }
void act_on_terminal( Terminal::Emulator *emu ) const;
};
class OSC_Put : public Action {
public:
void act_on_terminal( Terminal::Emulator* emu ) const;
};
class OSC_Put : public Action
{
public:
std::string name( void ) { return std::string( "OSC_Put" ); }
void act_on_terminal( Terminal::Emulator *emu ) const;
};
class OSC_End : public Action {
public:
void act_on_terminal( Terminal::Emulator* emu ) const;
};
class OSC_End : public Action
{
public:
std::string name( void ) { return std::string( "OSC_End" ); }
void act_on_terminal( Terminal::Emulator *emu ) const;
};
void act_on_terminal( Terminal::Emulator* emu ) const;
};
class UserByte : public Action {
class UserByte : public Action
{
/* user keystroke -- not part of the host-source state machine*/
public:
public:
char c; /* The user-source byte. We don't try to interpret the charset */
std::string name( void ) { return std::string( "UserByte" ); }
void act_on_terminal( Terminal::Emulator *emu ) const;
void act_on_terminal( Terminal::Emulator* emu ) const;
UserByte( int s_c ) : c( s_c ) {}
bool operator==( const UserByte &other ) const
{
return c == other.c;
}
};
bool operator==( const UserByte& other ) const { return c == other.c; }
};
class Resize : public Action {
class Resize : public Action
{
/* resize event -- not part of the host-source state machine*/
public:
public:
size_t width, height;
std::string name( void ) { return std::string( "Resize" ); }
void act_on_terminal( Terminal::Emulator *emu ) const;
void act_on_terminal( Terminal::Emulator* emu ) const;
Resize( size_t s_width, size_t s_height )
: width( s_width ),
height( s_height )
{}
Resize( size_t s_width, size_t s_height ) : width( s_width ), height( s_height ) {}
bool operator==( const Resize &other ) const
{
return ( width == other.width ) && ( height == other.height );
}
};
bool operator==( const Resize& other ) const { return ( width == other.width ) && ( height == other.height ); }
};
}
#endif
+40 -49
View File
@@ -39,16 +39,14 @@ using namespace Parser;
Transition State::anywhere_rule( wchar_t ch ) const
{
if ( (ch == 0x18) || (ch == 0x1A)
|| ((0x80 <= ch) && (ch <= 0x8F))
|| ((0x91 <= ch) && (ch <= 0x97))
|| (ch == 0x99) || (ch == 0x9A) ) {
if ( ( ch == 0x18 ) || ( ch == 0x1A ) || ( ( 0x80 <= ch ) && ( ch <= 0x8F ) )
|| ( ( 0x91 <= ch ) && ( ch <= 0x97 ) ) || ( ch == 0x99 ) || ( ch == 0x9A ) ) {
return Transition( std::make_shared<Execute>(), &family->s_Ground );
} else if ( ch == 0x9C ) {
return Transition( &family->s_Ground );
} else if ( ch == 0x1B ) {
return Transition( &family->s_Escape );
} else if ( (ch == 0x98) || (ch == 0x9E) || (ch == 0x9F) ) {
} else if ( ( ch == 0x98 ) || ( ch == 0x9E ) || ( ch == 0x9F ) ) {
return Transition( &family->s_SOS_PM_APC_String );
} else if ( ch == 0x90 ) {
return Transition( &family->s_DCS_Entry );
@@ -58,7 +56,7 @@ Transition State::anywhere_rule( wchar_t ch ) const
return Transition( &family->s_CSI_Entry );
}
return Transition(( State * )NULL, ActionPointer() ); /* don't allocate an Ignore action */
return Transition( (State*)NULL, ActionPointer() ); /* don't allocate an Ignore action */
}
Transition State::input( wchar_t ch ) const
@@ -80,15 +78,13 @@ Transition State::input( wchar_t ch ) const
static bool C0_prime( wchar_t ch )
{
return (ch <= 0x17)
|| (ch == 0x19)
|| ( (0x1C <= ch) && (ch <= 0x1F) );
return ( ch <= 0x17 ) || ( ch == 0x19 ) || ( ( 0x1C <= ch ) && ( ch <= 0x1F ) );
}
static bool GLGR ( wchar_t ch )
static bool GLGR( wchar_t ch )
{
return ( (0x20 <= ch) && (ch <= 0x7F) ) /* GL area */
|| ( (0xA0 <= ch) && (ch <= 0xFF) ); /* GR area */
return ( ( 0x20 <= ch ) && ( ch <= 0x7F ) ) /* GL area */
|| ( ( 0xA0 <= ch ) && ( ch <= 0xFF ) ); /* GR area */
}
Transition Ground::input_state_rule( wchar_t ch ) const
@@ -115,16 +111,12 @@ Transition Escape::input_state_rule( wchar_t ch ) const
return Transition( std::make_shared<Execute>() );
}
if ( (0x20 <= ch) && (ch <= 0x2F) ) {
if ( ( 0x20 <= ch ) && ( ch <= 0x2F ) ) {
return Transition( std::make_shared<Collect>(), &family->s_Escape_Intermediate );
}
if ( ( (0x30 <= ch) && (ch <= 0x4F) )
|| ( (0x51 <= ch) && (ch <= 0x57) )
|| ( ch == 0x59 )
|| ( ch == 0x5A )
|| ( ch == 0x5C )
|| ( (0x60 <= ch) && (ch <= 0x7E) ) ) {
if ( ( ( 0x30 <= ch ) && ( ch <= 0x4F ) ) || ( ( 0x51 <= ch ) && ( ch <= 0x57 ) ) || ( ch == 0x59 )
|| ( ch == 0x5A ) || ( ch == 0x5C ) || ( ( 0x60 <= ch ) && ( ch <= 0x7E ) ) ) {
return Transition( std::make_shared<Esc_Dispatch>(), &family->s_Ground );
}
@@ -140,7 +132,7 @@ Transition Escape::input_state_rule( wchar_t ch ) const
return Transition( &family->s_DCS_Entry );
}
if ( (ch == 0x58) || (ch == 0x5E) || (ch == 0x5F) ) {
if ( ( ch == 0x58 ) || ( ch == 0x5E ) || ( ch == 0x5F ) ) {
return Transition( &family->s_SOS_PM_APC_String );
}
@@ -153,11 +145,11 @@ Transition Escape_Intermediate::input_state_rule( wchar_t ch ) const
return Transition( std::make_shared<Execute>() );
}
if ( (0x20 <= ch) && (ch <= 0x2F) ) {
if ( ( 0x20 <= ch ) && ( ch <= 0x2F ) ) {
return Transition( std::make_shared<Collect>() );
}
if ( (0x30 <= ch) && (ch <= 0x7E) ) {
if ( ( 0x30 <= ch ) && ( ch <= 0x7E ) ) {
return Transition( std::make_shared<Esc_Dispatch>(), &family->s_Ground );
}
@@ -175,16 +167,15 @@ Transition CSI_Entry::input_state_rule( wchar_t ch ) const
return Transition( std::make_shared<Execute>() );
}
if ( (0x40 <= ch) && (ch <= 0x7E) ) {
if ( ( 0x40 <= ch ) && ( ch <= 0x7E ) ) {
return Transition( std::make_shared<CSI_Dispatch>(), &family->s_Ground );
}
if ( ( (0x30 <= ch) && (ch <= 0x39) )
|| ( ch == 0x3B ) ) {
if ( ( ( 0x30 <= ch ) && ( ch <= 0x39 ) ) || ( ch == 0x3B ) ) {
return Transition( std::make_shared<Param>(), &family->s_CSI_Param );
}
if ( (0x3C <= ch) && (ch <= 0x3F) ) {
if ( ( 0x3C <= ch ) && ( ch <= 0x3F ) ) {
return Transition( std::make_shared<Collect>(), &family->s_CSI_Param );
}
@@ -192,7 +183,7 @@ Transition CSI_Entry::input_state_rule( wchar_t ch ) const
return Transition( &family->s_CSI_Ignore );
}
if ( (0x20 <= ch) && (ch <= 0x2F) ) {
if ( ( 0x20 <= ch ) && ( ch <= 0x2F ) ) {
return Transition( std::make_shared<Collect>(), &family->s_CSI_Intermediate );
}
@@ -205,19 +196,19 @@ Transition CSI_Param::input_state_rule( wchar_t ch ) const
return Transition( std::make_shared<Execute>() );
}
if ( ( (0x30 <= ch) && (ch <= 0x39) ) || ( ch == 0x3B ) ) {
if ( ( ( 0x30 <= ch ) && ( ch <= 0x39 ) ) || ( ch == 0x3B ) ) {
return Transition( std::make_shared<Param>() );
}
if ( ( ch == 0x3A ) || ( (0x3C <= ch) && (ch <= 0x3F) ) ) {
if ( ( ch == 0x3A ) || ( ( 0x3C <= ch ) && ( ch <= 0x3F ) ) ) {
return Transition( &family->s_CSI_Ignore );
}
if ( (0x20 <= ch) && (ch <= 0x2F) ) {
if ( ( 0x20 <= ch ) && ( ch <= 0x2F ) ) {
return Transition( std::make_shared<Collect>(), &family->s_CSI_Intermediate );
}
if ( (0x40 <= ch) && (ch <= 0x7E) ) {
if ( ( 0x40 <= ch ) && ( ch <= 0x7E ) ) {
return Transition( std::make_shared<CSI_Dispatch>(), &family->s_Ground );
}
@@ -230,15 +221,15 @@ Transition CSI_Intermediate::input_state_rule( wchar_t ch ) const
return Transition( std::make_shared<Execute>() );
}
if ( (0x20 <= ch) && (ch <= 0x2F) ) {
if ( ( 0x20 <= ch ) && ( ch <= 0x2F ) ) {
return Transition( std::make_shared<Collect>() );
}
if ( (0x40 <= ch) && (ch <= 0x7E) ) {
if ( ( 0x40 <= ch ) && ( ch <= 0x7E ) ) {
return Transition( std::make_shared<CSI_Dispatch>(), &family->s_Ground );
}
if ( (0x30 <= ch) && (ch <= 0x3F) ) {
if ( ( 0x30 <= ch ) && ( ch <= 0x3F ) ) {
return Transition( &family->s_CSI_Ignore );
}
@@ -251,7 +242,7 @@ Transition CSI_Ignore::input_state_rule( wchar_t ch ) const
return Transition( std::make_shared<Execute>() );
}
if ( (0x40 <= ch) && (ch <= 0x7E) ) {
if ( ( 0x40 <= ch ) && ( ch <= 0x7E ) ) {
return Transition( &family->s_Ground );
}
@@ -265,7 +256,7 @@ ActionPointer DCS_Entry::enter( void ) const
Transition DCS_Entry::input_state_rule( wchar_t ch ) const
{
if ( (0x20 <= ch) && (ch <= 0x2F) ) {
if ( ( 0x20 <= ch ) && ( ch <= 0x2F ) ) {
return Transition( std::make_shared<Collect>(), &family->s_DCS_Intermediate );
}
@@ -273,15 +264,15 @@ Transition DCS_Entry::input_state_rule( wchar_t ch ) const
return Transition( &family->s_DCS_Ignore );
}
if ( ( (0x30 <= ch) && (ch <= 0x39) ) || ( ch == 0x3B ) ) {
if ( ( ( 0x30 <= ch ) && ( ch <= 0x39 ) ) || ( ch == 0x3B ) ) {
return Transition( std::make_shared<Param>(), &family->s_DCS_Param );
}
if ( (0x3C <= ch) && (ch <= 0x3F) ) {
if ( ( 0x3C <= ch ) && ( ch <= 0x3F ) ) {
return Transition( std::make_shared<Collect>(), &family->s_DCS_Param );
}
if ( (0x40 <= ch) && (ch <= 0x7E) ) {
if ( ( 0x40 <= ch ) && ( ch <= 0x7E ) ) {
return Transition( &family->s_DCS_Passthrough );
}
@@ -290,19 +281,19 @@ Transition DCS_Entry::input_state_rule( wchar_t ch ) const
Transition DCS_Param::input_state_rule( wchar_t ch ) const
{
if ( ( (0x30 <= ch) && (ch <= 0x39) ) || ( ch == 0x3B ) ) {
if ( ( ( 0x30 <= ch ) && ( ch <= 0x39 ) ) || ( ch == 0x3B ) ) {
return Transition( std::make_shared<Param>() );
}
if ( ( ch == 0x3A ) || ( (0x3C <= ch) && (ch <= 0x3F) ) ) {
if ( ( ch == 0x3A ) || ( ( 0x3C <= ch ) && ( ch <= 0x3F ) ) ) {
return Transition( &family->s_DCS_Ignore );
}
if ( (0x20 <= ch) && (ch <= 0x2F) ) {
if ( ( 0x20 <= ch ) && ( ch <= 0x2F ) ) {
return Transition( std::make_shared<Collect>(), &family->s_DCS_Intermediate );
}
if ( (0x40 <= ch) && (ch <= 0x7E) ) {
if ( ( 0x40 <= ch ) && ( ch <= 0x7E ) ) {
return Transition( &family->s_DCS_Passthrough );
}
@@ -311,15 +302,15 @@ Transition DCS_Param::input_state_rule( wchar_t ch ) const
Transition DCS_Intermediate::input_state_rule( wchar_t ch ) const
{
if ( (0x20 <= ch) && (ch <= 0x2F) ) {
if ( ( 0x20 <= ch ) && ( ch <= 0x2F ) ) {
return Transition( std::make_shared<Collect>() );
}
if ( (0x40 <= ch) && (ch <= 0x7E) ) {
if ( ( 0x40 <= ch ) && ( ch <= 0x7E ) ) {
return Transition( &family->s_DCS_Passthrough );
}
if ( (0x30 <= ch) && (ch <= 0x3F) ) {
if ( ( 0x30 <= ch ) && ( ch <= 0x3F ) ) {
return Transition( &family->s_DCS_Ignore );
}
@@ -338,7 +329,7 @@ ActionPointer DCS_Passthrough::exit( void ) const
Transition DCS_Passthrough::input_state_rule( wchar_t ch ) const
{
if ( C0_prime( ch ) || ( (0x20 <= ch) && (ch <= 0x7E) ) ) {
if ( C0_prime( ch ) || ( ( 0x20 <= ch ) && ( ch <= 0x7E ) ) ) {
return Transition( std::make_shared<Put>() );
}
@@ -370,11 +361,11 @@ ActionPointer OSC_String::exit( void ) const
Transition OSC_String::input_state_rule( wchar_t ch ) const
{
if ( (0x20 <= ch) && (ch <= 0x7F) ) {
if ( ( 0x20 <= ch ) && ( ch <= 0x7F ) ) {
return Transition( std::make_shared<OSC_Put>() );
}
if ( (ch == 0x9C) || (ch == 0x07) ) { /* 0x07 is xterm non-ANSI variant */
if ( ( ch == 0x9C ) || ( ch == 0x07 ) ) { /* 0x07 is xterm non-ANSI variant */
return Transition( &family->s_Ground );
}
+53 -39
View File
@@ -36,19 +36,19 @@
#include "parsertransition.h"
namespace Parser {
class StateFamily;
class StateFamily;
class State
{
protected:
class State
{
protected:
virtual Transition input_state_rule( wchar_t ch ) const = 0;
StateFamily *family;
StateFamily* family;
private:
private:
Transition anywhere_rule( wchar_t ch ) const;
public:
void setfamily( StateFamily *s_family ) { family = s_family; }
public:
void setfamily( StateFamily* s_family ) { family = s_family; }
Transition input( wchar_t ch ) const;
virtual ActionPointer enter( void ) const { return std::make_shared<Ignore>(); }
virtual ActionPointer exit( void ) const { return std::make_shared<Ignore>(); }
@@ -56,64 +56,78 @@ namespace Parser {
State() : family( NULL ) {};
virtual ~State() {};
State( const State & );
State & operator=( const State & );
};
State( const State& );
State& operator=( const State& );
};
class Ground : public State {
class Ground : public State
{
Transition input_state_rule( wchar_t ch ) const;
};
};
class Escape : public State {
class Escape : public State
{
ActionPointer enter( void ) const;
Transition input_state_rule( wchar_t ch ) const;
};
};
class Escape_Intermediate : public State {
class Escape_Intermediate : public State
{
Transition input_state_rule( wchar_t ch ) const;
};
};
class CSI_Entry : public State {
class CSI_Entry : public State
{
ActionPointer enter( void ) const;
Transition input_state_rule( wchar_t ch ) const;
};
class CSI_Param : public State {
};
class CSI_Param : public State
{
Transition input_state_rule( wchar_t ch ) const;
};
class CSI_Intermediate : public State {
};
class CSI_Intermediate : public State
{
Transition input_state_rule( wchar_t ch ) const;
};
class CSI_Ignore : public State {
};
class CSI_Ignore : public State
{
Transition input_state_rule( wchar_t ch ) const;
};
};
class DCS_Entry : public State {
class DCS_Entry : public State
{
ActionPointer enter( void ) const;
Transition input_state_rule( wchar_t ch ) const;
};
class DCS_Param : public State {
};
class DCS_Param : public State
{
Transition input_state_rule( wchar_t ch ) const;
};
class DCS_Intermediate : public State {
};
class DCS_Intermediate : public State
{
Transition input_state_rule( wchar_t ch ) const;
};
class DCS_Passthrough : public State {
};
class DCS_Passthrough : public State
{
ActionPointer enter( void ) const;
Transition input_state_rule( wchar_t ch ) const;
ActionPointer exit( void ) const;
};
class DCS_Ignore : public State {
};
class DCS_Ignore : public State
{
Transition input_state_rule( wchar_t ch ) const;
};
};
class OSC_String : public State {
class OSC_String : public State
{
ActionPointer enter( void ) const;
Transition input_state_rule( wchar_t ch ) const;
ActionPointer exit( void ) const;
};
class SOS_PM_APC_String : public State {
};
class SOS_PM_APC_String : public State
{
Transition input_state_rule( wchar_t ch ) const;
};
};
}
#endif
+6 -8
View File
@@ -36,9 +36,9 @@
#include "parserstate.h"
namespace Parser {
class StateFamily
{
public:
class StateFamily
{
public:
Ground s_Ground;
Escape s_Escape;
@@ -59,10 +59,8 @@ namespace Parser {
SOS_PM_APC_String s_SOS_PM_APC_String;
StateFamily()
: s_Ground(), s_Escape(), s_Escape_Intermediate(),
s_CSI_Entry(), s_CSI_Param(), s_CSI_Intermediate(), s_CSI_Ignore(),
s_DCS_Entry(), s_DCS_Param(), s_DCS_Intermediate(),
s_DCS_Passthrough(), s_DCS_Ignore(),
: s_Ground(), s_Escape(), s_Escape_Intermediate(), s_CSI_Entry(), s_CSI_Param(), s_CSI_Intermediate(),
s_CSI_Ignore(), s_DCS_Entry(), s_DCS_Param(), s_DCS_Intermediate(), s_DCS_Passthrough(), s_DCS_Ignore(),
s_OSC_String(), s_SOS_PM_APC_String()
{
s_Ground.setfamily( this );
@@ -80,7 +78,7 @@ namespace Parser {
s_OSC_String.setfamily( this );
s_SOS_PM_APC_String.setfamily( this );
}
};
};
}
#endif
+10 -12
View File
@@ -38,37 +38,35 @@
#include "src/terminal/parseraction.h"
namespace Parser {
class State;
class State;
class Transition
{
public:
class Transition
{
public:
// Transition is only a courier for an Action; it should
// never create/delete one on its own.
ActionPointer action;
State *next_state;
State* next_state;
Transition( const Transition &x )
: action( x.action ),
next_state( x.next_state ) {}
Transition & operator=( const Transition &t )
Transition( const Transition& x ) : action( x.action ), next_state( x.next_state ) {}
Transition& operator=( const Transition& t )
{
action = t.action;
next_state = t.next_state;
return *this;
}
Transition( ActionPointer s_action = std::make_shared<Ignore>(), State *s_next_state=NULL )
Transition( ActionPointer s_action = std::make_shared<Ignore>(), State* s_next_state = NULL )
: action( s_action ), next_state( s_next_state )
{}
// This is only ever used in the 1-argument form;
// we use this instead of an initializer to
// tell Coverity the object never owns *action.
Transition( State *s_next_state, ActionPointer s_action = std::make_shared<Ignore>() )
Transition( State* s_next_state, ActionPointer s_action = std::make_shared<Ignore>() )
: action( s_action ), next_state( s_next_state )
{}
};
};
}
#endif
+16 -23
View File
@@ -41,9 +41,7 @@
using namespace Terminal;
Emulator::Emulator( size_t s_width, size_t s_height )
: fb( s_width, s_height ), dispatch(), user()
{}
Emulator::Emulator( size_t s_width, size_t s_height ) : fb( s_width, s_height ), dispatch(), user() {}
std::string Emulator::read_octets_to_host( void )
{
@@ -52,12 +50,12 @@ std::string Emulator::read_octets_to_host( void )
return ret;
}
void Emulator::execute( const Parser::Execute *act )
void Emulator::execute( const Parser::Execute* act )
{
dispatch.dispatch( CONTROL, act, &fb );
}
void Emulator::print( const Parser::Print *act )
void Emulator::print( const Parser::Print* act )
{
assert( act->char_present );
@@ -67,9 +65,9 @@ void Emulator::print( const Parser::Print *act )
* Check for printing ISO 8859-1 first, it's a cheap way to detect
* some common narrow characters.
*/
const int chwidth = ch == L'\0' ? -1 : ( Cell::isprint_iso8859_1( ch ) ? 1 : wcwidth( ch ));
const int chwidth = ch == L'\0' ? -1 : ( Cell::isprint_iso8859_1( ch ) ? 1 : wcwidth( ch ) );
Cell *this_cell = fb.get_mutable_cell();
Cell* this_cell = fb.get_mutable_cell();
switch ( chwidth ) {
case 1: /* normal character */
@@ -79,9 +77,8 @@ void Emulator::print( const Parser::Print *act )
fb.ds.move_col( 0 );
fb.move_rows_autoscroll( 1 );
this_cell = NULL;
} else if ( fb.ds.auto_wrap_mode
&& (chwidth == 2)
&& (fb.ds.get_cursor_col() == fb.ds.get_width() - 1) ) {
} else if ( fb.ds.auto_wrap_mode && ( chwidth == 2 )
&& ( fb.ds.get_cursor_col() == fb.ds.get_width() - 1 ) ) {
/* wrap 2-cell chars if no room, even without will-wrap flag */
fb.reset_cell( this_cell );
fb.get_mutable_row( -1 )->set_wrap( false );
@@ -101,7 +98,7 @@ void Emulator::print( const Parser::Print *act )
this_cell = NULL;
}
if (!this_cell) {
if ( !this_cell ) {
this_cell = fb.get_mutable_cell();
}
@@ -110,8 +107,7 @@ void Emulator::print( const Parser::Print *act )
this_cell->set_wide( chwidth == 2 ); /* chwidth had better be 1 or 2 here */
fb.apply_renditions_to_cell( this_cell );
if ( chwidth == 2
&& fb.ds.get_cursor_col() + 1 < fb.ds.get_width() ) { /* erase overlapped cell */
if ( chwidth == 2 && fb.ds.get_cursor_col() + 1 < fb.ds.get_width() ) { /* erase overlapped cell */
fb.reset_cell( fb.get_mutable_cell( fb.ds.get_cursor_row(), fb.ds.get_cursor_col() + 1 ) );
}
@@ -120,7 +116,7 @@ void Emulator::print( const Parser::Print *act )
break;
case 0: /* combining character */
{
Cell *combining_cell = fb.get_combining_cell(); /* can be null if we were resized */
Cell* combining_cell = fb.get_combining_cell(); /* can be null if we were resized */
if ( combining_cell == NULL ) { /* character is now offscreen */
break;
}
@@ -138,8 +134,7 @@ void Emulator::print( const Parser::Print *act )
if ( !combining_cell->full() ) {
combining_cell->append( ch );
}
}
break;
} break;
case -1: /* unprintable character */
break;
default:
@@ -148,22 +143,20 @@ void Emulator::print( const Parser::Print *act )
}
}
void Emulator::CSI_dispatch( const Parser::CSI_Dispatch *act )
void Emulator::CSI_dispatch( const Parser::CSI_Dispatch* act )
{
dispatch.dispatch( CSI, act, &fb );
}
void Emulator::OSC_end( const Parser::OSC_End *act )
void Emulator::OSC_end( const Parser::OSC_End* act )
{
dispatch.OSC_dispatch( act, &fb );
}
void Emulator::Esc_dispatch( const Parser::Esc_Dispatch *act )
void Emulator::Esc_dispatch( const Parser::Esc_Dispatch* act )
{
/* handle 7-bit ESC-encoding of C1 control characters */
if ( (dispatch.get_dispatch_chars().size() == 0)
&& (0x40 <= act->ch)
&& (act->ch <= 0x5F) ) {
if ( ( dispatch.get_dispatch_chars().size() == 0 ) && ( 0x40 <= act->ch ) && ( act->ch <= 0x5F ) ) {
Parser::Esc_Dispatch act2 = *act;
act2.ch += 0x40;
dispatch.dispatch( CONTROL, &act2, &fb );
@@ -177,7 +170,7 @@ void Emulator::resize( size_t s_width, size_t s_height )
fb.resize( s_width, s_height );
}
bool Emulator::operator==( Emulator const &x ) const
bool Emulator::operator==( Emulator const& x ) const
{
/* dispatcher and user are irrelevant for us */
return fb == x.fb;
+25 -24
View File
@@ -41,47 +41,48 @@
#include "src/terminal/parseraction.h"
#include "src/terminal/terminalframebuffer.h"
#include "terminaldispatcher.h"
#include "terminaluserinput.h"
#include "terminaldisplay.h"
#include "terminaluserinput.h"
namespace Terminal {
class Emulator {
friend void Parser::Print::act_on_terminal( Emulator * ) const;
friend void Parser::Execute::act_on_terminal( Emulator * ) const;
friend void Parser::Clear::act_on_terminal( Emulator * ) const;
friend void Parser::Param::act_on_terminal( Emulator * ) const;
friend void Parser::Collect::act_on_terminal( Emulator * ) const;
friend void Parser::CSI_Dispatch::act_on_terminal( Emulator * ) const;
friend void Parser::Esc_Dispatch::act_on_terminal( Emulator * ) const;
friend void Parser::OSC_Start::act_on_terminal( Emulator * ) const;
friend void Parser::OSC_Put::act_on_terminal( Emulator * ) const;
friend void Parser::OSC_End::act_on_terminal( Emulator * ) const;
class Emulator
{
friend void Parser::Print::act_on_terminal( Emulator* ) const;
friend void Parser::Execute::act_on_terminal( Emulator* ) const;
friend void Parser::Clear::act_on_terminal( Emulator* ) const;
friend void Parser::Param::act_on_terminal( Emulator* ) const;
friend void Parser::Collect::act_on_terminal( Emulator* ) const;
friend void Parser::CSI_Dispatch::act_on_terminal( Emulator* ) const;
friend void Parser::Esc_Dispatch::act_on_terminal( Emulator* ) const;
friend void Parser::OSC_Start::act_on_terminal( Emulator* ) const;
friend void Parser::OSC_Put::act_on_terminal( Emulator* ) const;
friend void Parser::OSC_End::act_on_terminal( Emulator* ) const;
friend void Parser::UserByte::act_on_terminal( Emulator * ) const;
friend void Parser::Resize::act_on_terminal( Emulator * ) const;
friend void Parser::UserByte::act_on_terminal( Emulator* ) const;
friend void Parser::Resize::act_on_terminal( Emulator* ) const;
private:
private:
Framebuffer fb;
Dispatcher dispatch;
UserInput user;
/* action methods */
void print( const Parser::Print *act );
void execute( const Parser::Execute *act );
void CSI_dispatch( const Parser::CSI_Dispatch *act );
void Esc_dispatch( const Parser::Esc_Dispatch *act );
void OSC_end( const Parser::OSC_End *act );
void print( const Parser::Print* act );
void execute( const Parser::Execute* act );
void CSI_dispatch( const Parser::CSI_Dispatch* act );
void Esc_dispatch( const Parser::Esc_Dispatch* act );
void OSC_end( const Parser::OSC_End* act );
void resize( size_t s_width, size_t s_height );
public:
public:
Emulator( size_t s_width, size_t s_height );
std::string read_octets_to_host( void );
const Framebuffer & get_fb( void ) const { return fb; }
const Framebuffer& get_fb( void ) const { return fb; }
bool operator==( Emulator const &x ) const;
};
bool operator==( Emulator const& x ) const;
};
}
#endif
+41 -40
View File
@@ -36,23 +36,22 @@
#include <cstdlib>
#include <cstring>
#include "terminaldispatcher.h"
#include "src/terminal/parseraction.h"
#include "src/terminal/terminalframebuffer.h"
#include "terminaldispatcher.h"
using namespace Terminal;
static const size_t MAXIMUM_CLIPBOARD_SIZE = 16*1024;
static const size_t MAXIMUM_CLIPBOARD_SIZE = 16 * 1024;
Dispatcher::Dispatcher()
: params(), parsed_params(), parsed( false ), dispatch_chars(),
OSC_string(), terminal_to_host()
: params(), parsed_params(), parsed( false ), dispatch_chars(), OSC_string(), terminal_to_host()
{}
void Dispatcher::newparamchar( const Parser::Param *act )
void Dispatcher::newparamchar( const Parser::Param* act )
{
assert( act->char_present );
assert( (act->ch == ';') || ( (act->ch >= '0') && (act->ch <= '9') ) );
assert( ( act->ch == ';' ) || ( ( act->ch >= '0' ) && ( act->ch <= '9' ) ) );
if ( params.length() < 100 ) {
/* enough for 16 five-char params plus 15 semicolons */
params.push_back( act->ch );
@@ -60,7 +59,7 @@ void Dispatcher::newparamchar( const Parser::Param *act )
parsed = false;
}
void Dispatcher::collect( const Parser::Collect *act )
void Dispatcher::collect( const Parser::Collect* act )
{
assert( act->char_present );
if ( ( dispatch_chars.length() < 8 ) /* never should need more than 2 */
@@ -69,7 +68,7 @@ void Dispatcher::collect( const Parser::Collect *act )
}
}
void Dispatcher::clear( const Parser::Clear *act __attribute((unused)) )
void Dispatcher::clear( const Parser::Clear* act __attribute( ( unused ) ) )
{
params.clear();
dispatch_chars.clear();
@@ -83,17 +82,17 @@ void Dispatcher::parse_params( void )
}
parsed_params.clear();
const char *str = params.c_str();
const char *segment_begin = str;
const char* str = params.c_str();
const char* segment_begin = str;
while ( 1 ) {
const char *segment_end = strchr( segment_begin, ';' );
const char* segment_end = strchr( segment_begin, ';' );
if ( segment_end == NULL ) {
break;
}
errno = 0;
char *endptr;
char* endptr;
long val = strtol( segment_begin, &endptr, 10 );
if ( endptr == segment_begin ) {
val = -1;
@@ -113,7 +112,7 @@ void Dispatcher::parse_params( void )
/* get last param */
errno = 0;
char *endptr;
char* endptr;
long val = strtol( segment_begin, &endptr, 10 );
if ( endptr == segment_begin ) {
val = -1;
@@ -139,10 +138,11 @@ int Dispatcher::getparam( size_t N, int defaultval )
}
if ( parsed_params.size() > N ) {
ret = parsed_params[ N ];
ret = parsed_params[N];
}
if ( ret < 1 ) ret = defaultval;
if ( ret < 1 )
ret = defaultval;
return ret;
}
@@ -158,22 +158,19 @@ int Dispatcher::param_count( void )
std::string Dispatcher::str( void )
{
char assum[ 64 ];
snprintf( assum, 64, "[dispatch=\"%s\" params=\"%s\"]",
dispatch_chars.c_str(), params.c_str() );
char assum[64];
snprintf( assum, 64, "[dispatch=\"%s\" params=\"%s\"]", dispatch_chars.c_str(), params.c_str() );
return std::string( assum );
}
/* construct on first use to avoid static initialization order crash */
DispatchRegistry & Terminal::get_global_dispatch_registry( void )
DispatchRegistry& Terminal::get_global_dispatch_registry( void )
{
static DispatchRegistry global_dispatch_registry;
return global_dispatch_registry;
}
static void register_function( Function_Type type,
const std::string & dispatch_chars,
Function f )
static void register_function( Function_Type type, const std::string& dispatch_chars, Function f )
{
switch ( type ) {
case ESCAPE:
@@ -188,18 +185,19 @@ static void register_function( Function_Type type,
}
}
Function::Function( Function_Type type, const std::string & dispatch_chars,
void (*s_function)( Framebuffer *, Dispatcher * ),
Function::Function( Function_Type type,
const std::string& dispatch_chars,
void ( *s_function )( Framebuffer*, Dispatcher* ),
bool s_clears_wrap_state )
: function( s_function ), clears_wrap_state( s_clears_wrap_state )
{
register_function( type, dispatch_chars, *this );
}
void Dispatcher::dispatch( Function_Type type, const Parser::Action *act, Framebuffer *fb )
void Dispatcher::dispatch( Function_Type type, const Parser::Action* act, Framebuffer* fb )
{
/* add final char to dispatch key */
if ( (type == ESCAPE) || (type == CSI) ) {
if ( ( type == ESCAPE ) || ( type == CSI ) ) {
assert( act->char_present );
Parser::Collect act2;
act2.char_present = true;
@@ -207,17 +205,23 @@ void Dispatcher::dispatch( Function_Type type, const Parser::Action *act, Frameb
collect( &act2 );
}
dispatch_map_t *map = NULL;
dispatch_map_t* map = NULL;
switch ( type ) {
case ESCAPE: map = &get_global_dispatch_registry().escape; break;
case CSI: map = &get_global_dispatch_registry().CSI; break;
case CONTROL: map = &get_global_dispatch_registry().control; break;
case ESCAPE:
map = &get_global_dispatch_registry().escape;
break;
case CSI:
map = &get_global_dispatch_registry().CSI;
break;
case CONTROL:
map = &get_global_dispatch_registry().control;
break;
}
std::string key = dispatch_chars;
if ( type == CONTROL ) {
assert( act->ch <= 255 );
char ctrlstr[ 2 ] = { (char)act->ch, 0 };
char ctrlstr[2] = { (char)act->ch, 0 };
key = std::string( ctrlstr, 1 );
}
@@ -233,25 +237,22 @@ void Dispatcher::dispatch( Function_Type type, const Parser::Action *act, Frameb
i->second.function( fb, this );
}
void Dispatcher::OSC_put( const Parser::OSC_Put *act )
void Dispatcher::OSC_put( const Parser::OSC_Put* act )
{
assert( act->char_present );
if ( OSC_string.size() < MAXIMUM_CLIPBOARD_SIZE) {
if ( OSC_string.size() < MAXIMUM_CLIPBOARD_SIZE ) {
OSC_string.push_back( act->ch );
}
}
void Dispatcher::OSC_start( const Parser::OSC_Start *act __attribute((unused)) )
void Dispatcher::OSC_start( const Parser::OSC_Start* act __attribute( ( unused ) ) )
{
OSC_string.clear();
}
bool Dispatcher::operator==( const Dispatcher &x ) const
bool Dispatcher::operator==( const Dispatcher& x ) const
{
return ( params == x.params )
&& ( parsed_params == x.parsed_params )
&& ( parsed == x.parsed )
&& ( dispatch_chars == x.dispatch_chars )
&& ( OSC_string == x.OSC_string )
return ( params == x.params ) && ( parsed_params == x.parsed_params ) && ( parsed == x.parsed )
&& ( dispatch_chars == x.dispatch_chars ) && ( OSC_string == x.OSC_string )
&& ( terminal_to_host == x.terminal_to_host );
}
+47 -38
View File
@@ -33,54 +33,63 @@
#ifndef TERMINALDISPATCHER_HPP
#define TERMINALDISPATCHER_HPP
#include <vector>
#include <string>
#include <map>
#include <string>
#include <vector>
namespace Parser {
class Action;
class Param;
class Collect;
class Clear;
class Esc_Dispatch;
class CSI_Dispatch;
class Execute;
class OSC_Start;
class OSC_Put;
class OSC_End;
class Action;
class Param;
class Collect;
class Clear;
class Esc_Dispatch;
class CSI_Dispatch;
class Execute;
class OSC_Start;
class OSC_Put;
class OSC_End;
}
namespace Terminal {
class Framebuffer;
class Dispatcher;
class Framebuffer;
class Dispatcher;
enum Function_Type { ESCAPE, CSI, CONTROL };
enum Function_Type
{
ESCAPE,
CSI,
CONTROL
};
class Function {
public:
class Function
{
public:
Function() : function( NULL ), clears_wrap_state( true ) {}
Function( Function_Type type, const std::string & dispatch_chars,
void (*s_function)( Framebuffer *, Dispatcher * ),
Function( Function_Type type,
const std::string& dispatch_chars,
void ( *s_function )( Framebuffer*, Dispatcher* ),
bool s_clears_wrap_state = true );
void (*function)( Framebuffer *, Dispatcher * );
void ( *function )( Framebuffer*, Dispatcher* );
bool clears_wrap_state;
};
};
using dispatch_map_t = std::map<std::string, Function>;
using dispatch_map_t = std::map<std::string, Function>;
class DispatchRegistry {
public:
class DispatchRegistry
{
public:
dispatch_map_t escape;
dispatch_map_t CSI;
dispatch_map_t control;
DispatchRegistry() : escape(), CSI(), control() {}
};
};
DispatchRegistry & get_global_dispatch_registry( void );
DispatchRegistry& get_global_dispatch_registry( void );
class Dispatcher {
private:
class Dispatcher
{
private:
std::string params;
std::vector<int> parsed_params;
bool parsed;
@@ -90,7 +99,7 @@ namespace Terminal {
void parse_params( void );
public:
public:
static const int PARAM_MAX = 65535;
/* prevent evil escape sequences from causing long loops */
@@ -100,22 +109,22 @@ namespace Terminal {
int getparam( size_t N, int defaultval );
int param_count( void );
void newparamchar( const Parser::Param *act );
void collect( const Parser::Collect *act );
void clear( const Parser::Clear *act );
void newparamchar( const Parser::Param* act );
void collect( const Parser::Collect* act );
void clear( const Parser::Clear* act );
std::string str( void );
void dispatch( Function_Type type, const Parser::Action *act, Framebuffer *fb );
void dispatch( Function_Type type, const Parser::Action* act, Framebuffer* fb );
std::string get_dispatch_chars( void ) const { return dispatch_chars; }
std::vector<wchar_t> get_OSC_string( void ) const { return OSC_string; }
void OSC_put( const Parser::OSC_Put *act );
void OSC_start( const Parser::OSC_Start *act );
void OSC_dispatch( const Parser::OSC_End *act, Framebuffer *fb );
void OSC_put( const Parser::OSC_Put* act );
void OSC_start( const Parser::OSC_Start* act );
void OSC_dispatch( const Parser::OSC_End* act, Framebuffer* fb );
bool operator==( const Dispatcher &x ) const;
};
bool operator==( const Dispatcher& x ) const;
};
}
#endif
+79 -100
View File
@@ -32,14 +32,14 @@
#include <cstdio>
#include "terminaldisplay.h"
#include "src/terminal/terminalframebuffer.h"
#include "terminaldisplay.h"
using namespace Terminal;
/* Print a new "frame" to the terminal, using ANSI/ECMA-48 escape codes. */
static const Renditions & initial_rendition( void )
static const Renditions& initial_rendition( void )
{
const static Renditions blank = Renditions( 0 );
return blank;
@@ -54,15 +54,15 @@ std::string Display::close() const
{
return std::string( "\033[?1l\033[0m\033[?25h"
"\033[?1003l\033[?1002l\033[?1001l\033[?1000l"
"\033[?1015l\033[?1006l\033[?1005l" ) +
std::string( rmcup ? rmcup : "" );
"\033[?1015l\033[?1006l\033[?1005l" )
+ std::string( rmcup ? rmcup : "" );
}
std::string Display::new_frame( bool initialized, const Framebuffer &last, const Framebuffer &f ) const
std::string Display::new_frame( bool initialized, const Framebuffer& last, const Framebuffer& f ) const
{
FrameState frame( last );
char tmp[ 64 ];
char tmp[64];
/* has bell been rung? */
if ( f.get_bell_count() != frame.last_frame.get_bell_count() ) {
@@ -71,18 +71,15 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
using title_type = Terminal::Framebuffer::title_type;
/* has icon name or window title changed? */
if ( has_title && f.is_title_initialized() &&
( (!initialized)
|| (f.get_icon_name() != frame.last_frame.get_icon_name())
|| (f.get_window_title() != frame.last_frame.get_window_title()) ) ) {
if ( has_title && f.is_title_initialized()
&& ( ( !initialized ) || ( f.get_icon_name() != frame.last_frame.get_icon_name() )
|| ( f.get_window_title() != frame.last_frame.get_window_title() ) ) ) {
/* set icon name and window title */
if ( f.get_icon_name() == f.get_window_title() ) {
/* write combined Icon Name and Window Title */
frame.append( "\033]0;" );
const title_type &window_title( f.get_window_title() );
for ( title_type::const_iterator i = window_title.begin();
i != window_title.end();
i++ ) {
const title_type& window_title( f.get_window_title() );
for ( title_type::const_iterator i = window_title.begin(); i != window_title.end(); i++ ) {
frame.append( *i );
}
frame.append( '\007' );
@@ -90,50 +87,41 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
} else {
/* write Icon Name */
frame.append( "\033]1;" );
const title_type &icon_name( f.get_icon_name() );
for ( title_type::const_iterator i = icon_name.begin();
i != icon_name.end();
i++ ) {
const title_type& icon_name( f.get_icon_name() );
for ( title_type::const_iterator i = icon_name.begin(); i != icon_name.end(); i++ ) {
frame.append( *i );
}
frame.append( '\007' );
frame.append( "\033]2;" );
const title_type &window_title( f.get_window_title() );
for ( title_type::const_iterator i = window_title.begin();
i != window_title.end();
i++ ) {
const title_type& window_title( f.get_window_title() );
for ( title_type::const_iterator i = window_title.begin(); i != window_title.end(); i++ ) {
frame.append( *i );
}
frame.append( '\007' );
}
}
/* has clipboard changed? */
if (f.get_clipboard() != frame.last_frame.get_clipboard()) {
if ( f.get_clipboard() != frame.last_frame.get_clipboard() ) {
frame.append( "\033]52;c;" );
const title_type &clipboard( f.get_clipboard() );
for ( title_type::const_iterator i = clipboard.begin();
i != clipboard.end();
i++ ) {
const title_type& clipboard( f.get_clipboard() );
for ( title_type::const_iterator i = clipboard.begin(); i != clipboard.end(); i++ ) {
frame.append( *i );
}
frame.append( '\007' );
}
/* has reverse video state changed? */
if ( (!initialized)
|| (f.ds.reverse_video != frame.last_frame.ds.reverse_video) ) {
if ( ( !initialized ) || ( f.ds.reverse_video != frame.last_frame.ds.reverse_video ) ) {
/* set reverse video */
snprintf( tmp, 64, "\033[?5%c", (f.ds.reverse_video ? 'h' : 'l') );
snprintf( tmp, 64, "\033[?5%c", ( f.ds.reverse_video ? 'h' : 'l' ) );
frame.append( tmp );
}
/* has size changed? */
if ( (!initialized)
|| (f.ds.get_width() != frame.last_frame.ds.get_width())
|| (f.ds.get_height() != frame.last_frame.ds.get_height()) ) {
if ( ( !initialized ) || ( f.ds.get_width() != frame.last_frame.ds.get_width() )
|| ( f.ds.get_height() != frame.last_frame.ds.get_height() ) ) {
/* reset scrolling region */
frame.append( "\033[r" );
@@ -161,7 +149,7 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
if ( frame.last_frame.ds.get_width() < f.ds.get_width() ) {
for ( Framebuffer::rows_type::iterator p = rows.begin(); p != rows.end(); p++ ) {
*p = std::make_shared<Row>( **p );
(*p)->cells.resize( f.ds.get_width(), Cell( f.ds.get_background_rendition() ) );
( *p )->cells.resize( f.ds.get_width(), Cell( f.ds.get_background_rendition() ) );
}
}
/* Add rows if we've gotten a resize and new is taller than old */
@@ -179,9 +167,9 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
int scroll_height = 0;
for ( int row = 0; row < f.ds.get_height(); row++ ) {
const Row *new_row = f.get_row( 0 );
const Row *old_row = &*rows.at( row );
if ( ! ( new_row == old_row || *new_row == *old_row ) ) {
const Row* new_row = f.get_row( 0 );
const Row* old_row = &*rows.at( row );
if ( !( new_row == old_row || *new_row == *old_row ) ) {
continue;
}
/* if row 0, we're looking at ourselves and probably didn't scroll */
@@ -193,11 +181,8 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
scroll_height = 1;
/* how big is the region that was scrolled? */
for ( int region_height = 1;
lines_scrolled + region_height < f.ds.get_height();
region_height++ ) {
if ( *f.get_row( region_height )
== *rows.at( lines_scrolled + region_height ) ) {
for ( int region_height = 1; lines_scrolled + region_height < f.ds.get_height(); region_height++ ) {
if ( *f.get_row( region_height ) == *rows.at( lines_scrolled + region_height ) ) {
scroll_height = region_height + 1;
} else {
break;
@@ -227,15 +212,13 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
/* Common case: if we're already on the bottom line and we're scrolling the whole
* screen, just do a CR and LFs.
*/
if ( scroll_height + lines_scrolled == f.ds.get_height()
&& frame.cursor_y + 1 == f.ds.get_height() ) {
if ( scroll_height + lines_scrolled == f.ds.get_height() && frame.cursor_y + 1 == f.ds.get_height() ) {
frame.append( '\r' );
frame.append( lines_scrolled, '\n' );
frame.cursor_x = 0;
} else {
/* set scrolling region */
snprintf( tmp, 64, "\033[%d;%dr",
top_margin + 1, bottom_margin + 1);
snprintf( tmp, 64, "\033[%d;%dr", top_margin + 1, bottom_margin + 1 );
frame.append( tmp );
/* go to bottom of scrolling region */
@@ -270,15 +253,13 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
}
/* has cursor location changed? */
if ( (!initialized)
|| (f.ds.get_cursor_row() != frame.cursor_y)
|| (f.ds.get_cursor_col() != frame.cursor_x) ) {
if ( ( !initialized ) || ( f.ds.get_cursor_row() != frame.cursor_y )
|| ( f.ds.get_cursor_col() != frame.cursor_x ) ) {
frame.append_move( f.ds.get_cursor_row(), f.ds.get_cursor_col() );
}
/* has cursor visibility changed? */
if ( (!initialized)
|| (f.ds.cursor_visible != frame.cursor_visible) ) {
if ( ( !initialized ) || ( f.ds.cursor_visible != frame.cursor_visible ) ) {
if ( f.ds.cursor_visible ) {
frame.append( "\033[?25h" );
} else {
@@ -290,67 +271,68 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
frame.update_rendition( f.ds.get_renditions(), !initialized );
/* has bracketed paste mode changed? */
if ( (!initialized)
|| (f.ds.bracketed_paste != frame.last_frame.ds.bracketed_paste) ) {
if ( ( !initialized ) || ( f.ds.bracketed_paste != frame.last_frame.ds.bracketed_paste ) ) {
frame.append( f.ds.bracketed_paste ? "\033[?2004h" : "\033[?2004l" );
}
/* has mouse reporting mode changed? */
if ( (!initialized)
|| (f.ds.mouse_reporting_mode != frame.last_frame.ds.mouse_reporting_mode) ) {
if (f.ds.mouse_reporting_mode == DrawState::MOUSE_REPORTING_NONE) {
frame.append("\033[?1003l");
frame.append("\033[?1002l");
frame.append("\033[?1001l");
frame.append("\033[?1000l");
if ( ( !initialized ) || ( f.ds.mouse_reporting_mode != frame.last_frame.ds.mouse_reporting_mode ) ) {
if ( f.ds.mouse_reporting_mode == DrawState::MOUSE_REPORTING_NONE ) {
frame.append( "\033[?1003l" );
frame.append( "\033[?1002l" );
frame.append( "\033[?1001l" );
frame.append( "\033[?1000l" );
} else {
if (frame.last_frame.ds.mouse_reporting_mode != DrawState::MOUSE_REPORTING_NONE) {
snprintf(tmp, sizeof(tmp), "\033[?%dl", frame.last_frame.ds.mouse_reporting_mode);
frame.append(tmp);
if ( frame.last_frame.ds.mouse_reporting_mode != DrawState::MOUSE_REPORTING_NONE ) {
snprintf( tmp, sizeof( tmp ), "\033[?%dl", frame.last_frame.ds.mouse_reporting_mode );
frame.append( tmp );
}
snprintf(tmp, sizeof(tmp), "\033[?%dh", f.ds.mouse_reporting_mode);
frame.append(tmp);
snprintf( tmp, sizeof( tmp ), "\033[?%dh", f.ds.mouse_reporting_mode );
frame.append( tmp );
}
}
/* has mouse focus mode changed? */
if ( (!initialized)
|| (f.ds.mouse_focus_event != frame.last_frame.ds.mouse_focus_event) ) {
if ( ( !initialized ) || ( f.ds.mouse_focus_event != frame.last_frame.ds.mouse_focus_event ) ) {
frame.append( f.ds.mouse_focus_event ? "\033[?1004h" : "\033[?1004l" );
}
/* has mouse encoding mode changed? */
if ( (!initialized)
|| (f.ds.mouse_encoding_mode != frame.last_frame.ds.mouse_encoding_mode) ) {
if (f.ds.mouse_encoding_mode == DrawState::MOUSE_ENCODING_DEFAULT) {
frame.append("\033[?1015l");
frame.append("\033[?1006l");
frame.append("\033[?1005l");
if ( ( !initialized ) || ( f.ds.mouse_encoding_mode != frame.last_frame.ds.mouse_encoding_mode ) ) {
if ( f.ds.mouse_encoding_mode == DrawState::MOUSE_ENCODING_DEFAULT ) {
frame.append( "\033[?1015l" );
frame.append( "\033[?1006l" );
frame.append( "\033[?1005l" );
} else {
if (frame.last_frame.ds.mouse_encoding_mode != DrawState::MOUSE_ENCODING_DEFAULT) {
snprintf(tmp, sizeof(tmp), "\033[?%dl", frame.last_frame.ds.mouse_encoding_mode);
frame.append(tmp);
if ( frame.last_frame.ds.mouse_encoding_mode != DrawState::MOUSE_ENCODING_DEFAULT ) {
snprintf( tmp, sizeof( tmp ), "\033[?%dl", frame.last_frame.ds.mouse_encoding_mode );
frame.append( tmp );
}
snprintf(tmp, sizeof(tmp), "\033[?%dh", f.ds.mouse_encoding_mode);
frame.append(tmp);
snprintf( tmp, sizeof( tmp ), "\033[?%dh", f.ds.mouse_encoding_mode );
frame.append( tmp );
}
}
return frame.str;
}
bool Display::put_row( bool initialized, FrameState &frame, const Framebuffer &f, int frame_y, const Row &old_row, bool wrap ) const
bool Display::put_row( bool initialized,
FrameState& frame,
const Framebuffer& f,
int frame_y,
const Row& old_row,
bool wrap ) const
{
char tmp[ 64 ];
char tmp[64];
int frame_x = 0;
const Row &row = *f.get_row( frame_y );
const Row::cells_type &cells = row.cells;
const Row::cells_type &old_cells = old_row.cells;
const Row& row = *f.get_row( frame_y );
const Row::cells_type& cells = row.cells;
const Row::cells_type& old_cells = old_row.cells;
/* If we're forced to write the first column because of wrap, go ahead and do so. */
if ( wrap ) {
const Cell &cell = cells.at( 0 );
const Cell& cell = cells.at( 0 );
frame.update_rendition( cell.get_renditions() );
frame.append_cell( cell );
frame_x += cell.get_width();
@@ -358,7 +340,7 @@ bool Display::put_row( bool initialized, FrameState &frame, const Framebuffer &f
}
/* If rows are the same object, we don't need to do anything at all. */
if (initialized && &row == &old_row ) {
if ( initialized && &row == &old_row ) {
return false;
}
@@ -371,12 +353,10 @@ bool Display::put_row( bool initialized, FrameState &frame, const Framebuffer &f
/* iterate for every cell */
while ( frame_x < row_width ) {
const Cell &cell = cells.at( frame_x );
const Cell& cell = cells.at( frame_x );
/* Does cell need to be drawn? Skip all this. */
if ( initialized
&& !clear_count
&& ( cell == old_cells.at( frame_x ) ) ) {
if ( initialized && !clear_count && ( cell == old_cells.at( frame_x ) ) ) {
frame_x += cell.get_width();
continue;
}
@@ -418,7 +398,6 @@ bool Display::put_row( bool initialized, FrameState &frame, const Framebuffer &f
}
}
/* Now draw a character cell. */
/* Move to the right position. */
const int cell_width = cell.get_width();
@@ -460,8 +439,7 @@ bool Display::put_row( bool initialized, FrameState &frame, const Framebuffer &f
}
}
if ( ! ( wrote_last_cell
&& (frame_y < f.ds.get_height() - 1) ) ) {
if ( !( wrote_last_cell && ( frame_y < f.ds.get_height() - 1 ) ) ) {
return false;
}
/* To hint that a word-select should group the end of one line
@@ -480,9 +458,8 @@ bool Display::put_row( bool initialized, FrameState &frame, const Framebuffer &f
return false;
}
FrameState::FrameState( const Framebuffer &s_last )
: str(), cursor_x(0), cursor_y(0), current_rendition( 0 ),
cursor_visible( s_last.ds.cursor_visible ),
FrameState::FrameState( const Framebuffer& s_last )
: str(), cursor_x( 0 ), cursor_y( 0 ), current_rendition( 0 ), cursor_visible( s_last.ds.cursor_visible ),
last_frame( s_last )
{
/* Preallocate for better performance. Make a guess-- doesn't matter for correctness */
@@ -491,7 +468,8 @@ FrameState::FrameState( const Framebuffer &s_last )
void FrameState::append_silent_move( int y, int x )
{
if ( cursor_x == x && cursor_y == y ) return;
if ( cursor_x == x && cursor_y == y )
return;
/* turn off cursor if necessary before moving cursor */
if ( cursor_visible ) {
append( "\033[?25l" );
@@ -523,13 +501,14 @@ void FrameState::append_move( int y, int x )
}
// More optimizations are possible.
}
char tmp[ 64 ];
char tmp[64];
snprintf( tmp, 64, "\033[%d;%dH", y + 1, x + 1 );
append( tmp );
}
void FrameState::update_rendition(const Renditions &r, bool force) {
if ( force || !(current_rendition == r) ) {
void FrameState::update_rendition( const Renditions& r, bool force )
{
if ( force || !( current_rendition == r ) ) {
/* print renditions */
append_string( r.sgr() );
current_rendition = r;
+23 -16
View File
@@ -36,33 +36,35 @@
#include "src/terminal/terminalframebuffer.h"
namespace Terminal {
/* variables used within a new_frame */
class FrameState {
public:
/* variables used within a new_frame */
class FrameState
{
public:
std::string str;
int cursor_x, cursor_y;
Renditions current_rendition;
bool cursor_visible;
const Framebuffer &last_frame;
const Framebuffer& last_frame;
FrameState( const Framebuffer &s_last );
FrameState( const Framebuffer& s_last );
void append( char c ) { str.append( 1, c ); }
void append( size_t s, char c ) { str.append( s, c ); }
void append( wchar_t wc ) { Cell::append_to_str( str, wc ); }
void append( const char * s ) { str.append( s ); }
void append_string( const std::string &append ) { str.append(append); }
void append( const char* s ) { str.append( s ); }
void append_string( const std::string& append ) { str.append( append ); }
void append_cell(const Cell & cell) { cell.print_grapheme( str ); }
void append_cell( const Cell& cell ) { cell.print_grapheme( str ); }
void append_silent_move( int y, int x );
void append_move( int y, int x );
void update_rendition( const Renditions &r, bool force = false );
};
void update_rendition( const Renditions& r, bool force = false );
};
class Display {
private:
class Display
{
private:
bool has_ech; /* erase character is part of vt200 but not supported by tmux
(or by "screen" terminfo entry, which is what tmux advertises) */
@@ -72,16 +74,21 @@ namespace Terminal {
const char *smcup, *rmcup; /* enter and exit alternate screen mode */
bool put_row( bool initialized, FrameState &frame, const Framebuffer &f, int frame_y, const Row &old_row, bool wrap ) const;
bool put_row( bool initialized,
FrameState& frame,
const Framebuffer& f,
int frame_y,
const Row& old_row,
bool wrap ) const;
public:
public:
std::string open() const;
std::string close() const;
std::string new_frame( bool initialized, const Framebuffer &last, const Framebuffer &f ) const;
std::string new_frame( bool initialized, const Framebuffer& last, const Framebuffer& f ) const;
Display( bool use_environment );
};
};
}
#endif
+25 -29
View File
@@ -36,45 +36,45 @@
#include "src/include/config.h"
#include "terminaldisplay.h"
#include <string>
#include <stdexcept>
#include <string>
#if defined HAVE_NCURSESW_CURSES_H
# include <ncursesw/curses.h>
# include <ncursesw/term.h>
#include <ncursesw/curses.h>
#include <ncursesw/term.h>
#elif defined HAVE_NCURSESW_H
# include <ncursesw.h>
# include <term.h>
#include <ncursesw.h>
#include <term.h>
#elif defined HAVE_NCURSES_CURSES_H
# include <ncurses/curses.h>
# include <ncurses/term.h>
#include <ncurses/curses.h>
#include <ncurses/term.h>
#elif defined HAVE_NCURSES_H
# include <ncurses.h>
# include <term.h>
#include <ncurses.h>
#include <term.h>
#elif defined HAVE_CURSES_H
# include <curses.h>
# include <term.h>
#include <curses.h>
#include <term.h>
#else
# error "SysV or X/Open-compatible Curses header file required"
#error "SysV or X/Open-compatible Curses header file required"
#endif
#include <cstdlib>
#include <cstring>
using namespace Terminal;
static bool ti_flag( const char *capname )
static bool ti_flag( const char* capname )
{
int val = tigetflag( const_cast<char *>( capname ) );
int val = tigetflag( const_cast<char*>( capname ) );
if ( val == -1 ) {
throw std::invalid_argument( std::string( "Invalid terminfo boolean capability " ) + capname );
}
return val;
}
static const char *ti_str( const char *capname )
static const char* ti_str( const char* capname )
{
const char *val = tigetstr( const_cast<char *>( capname ) );
if ( val == (const char *)-1 ) {
const char* val = tigetstr( const_cast<char*>( capname ) );
if ( val == (const char*)-1 ) {
throw std::invalid_argument( std::string( "Invalid terminfo string capability " ) + capname );
}
return val;
@@ -85,7 +85,7 @@ Display::Display( bool use_environment )
{
if ( use_environment ) {
int errret = -2;
int ret = setupterm( (char *)0, 1, &errret );
int ret = setupterm( (char*)0, 1, &errret );
if ( ret != OK ) {
switch ( errret ) {
@@ -113,18 +113,14 @@ Display::Display( bool use_environment )
/* Check if we can set the window title and icon name. terminfo does not
have reliable information on this, so we hardcode a whitelist of
terminal type prefixes. */
static const char * const title_term_types[] = {
"xterm", "rxvt", "kterm", "Eterm", "alacritty", "screen", "tmux"
};
static const char* const title_term_types[]
= { "xterm", "rxvt", "kterm", "Eterm", "alacritty", "screen", "tmux" };
has_title = false;
const char *term_type = getenv( "TERM" );
const char* term_type = getenv( "TERM" );
if ( term_type ) {
for ( size_t i = 0;
i < sizeof( title_term_types ) / sizeof( const char * );
i++ ) {
if ( 0 == strncmp( term_type, title_term_types[ i ],
strlen( title_term_types[ i ] ) ) ) {
for ( size_t i = 0; i < sizeof( title_term_types ) / sizeof( const char* ); i++ ) {
if ( 0 == strncmp( term_type, title_term_types[i], strlen( title_term_types[i] ) ) ) {
has_title = true;
break;
}
@@ -132,8 +128,8 @@ Display::Display( bool use_environment )
}
if ( !getenv( "MOSH_NO_TERM_INIT" ) ) {
smcup = ti_str("smcup");
rmcup = ti_str("rmcup");
smcup = ti_str( "smcup" );
rmcup = ti_str( "rmcup" );
}
}
}
+127 -115
View File
@@ -39,11 +39,7 @@
using namespace Terminal;
Cell::Cell( color_type background_color )
: contents(),
renditions( background_color ),
wide( false ),
fallback( false ),
wrap( false )
: contents(), renditions( background_color ), wide( false ), fallback( false ), wrap( false )
{}
void Cell::reset( color_type background_color )
@@ -59,42 +55,40 @@ void DrawState::reinitialize_tabs( unsigned int start )
{
assert( default_tabs );
for ( unsigned int i = start; i < tabs.size(); i++ ) {
tabs[ i ] = ( (i % 8) == 0 );
tabs[i] = ( ( i % 8 ) == 0 );
}
}
DrawState::DrawState( int s_width, int s_height )
: width( s_width ), height( s_height ),
cursor_col( 0 ), cursor_row( 0 ),
combining_char_col( 0 ), combining_char_row( 0 ), default_tabs( true ), tabs( s_width ),
scrolling_region_top_row( 0 ), scrolling_region_bottom_row( height - 1 ),
renditions( 0 ), save(),
next_print_will_wrap( false ), origin_mode( false ), auto_wrap_mode( true ),
insert_mode( false ), cursor_visible( true ), reverse_video( false ),
bracketed_paste( false ), mouse_reporting_mode( MOUSE_REPORTING_NONE ), mouse_focus_event( false ),
mouse_alternate_scroll( false ), mouse_encoding_mode( MOUSE_ENCODING_DEFAULT ), application_mode_cursor_keys( false )
: width( s_width ), height( s_height ), cursor_col( 0 ), cursor_row( 0 ), combining_char_col( 0 ),
combining_char_row( 0 ), default_tabs( true ), tabs( s_width ), scrolling_region_top_row( 0 ),
scrolling_region_bottom_row( height - 1 ), renditions( 0 ), save(), next_print_will_wrap( false ),
origin_mode( false ), auto_wrap_mode( true ), insert_mode( false ), cursor_visible( true ),
reverse_video( false ), bracketed_paste( false ), mouse_reporting_mode( MOUSE_REPORTING_NONE ),
mouse_focus_event( false ), mouse_alternate_scroll( false ), mouse_encoding_mode( MOUSE_ENCODING_DEFAULT ),
application_mode_cursor_keys( false )
{
reinitialize_tabs( 0 );
}
Framebuffer::Framebuffer( int s_width, int s_height )
: rows(), icon_name(), window_title(), clipboard(), bell_count( 0 ), title_initialized( false ), ds( s_width, s_height )
: rows(), icon_name(), window_title(), clipboard(), bell_count( 0 ), title_initialized( false ),
ds( s_width, s_height )
{
assert( s_height > 0 );
assert( s_width > 0 );
const size_t w = s_width;
const color_type c = 0;
rows = rows_type(s_height, row_pointer(std::make_shared<Row>( w, c )));
rows = rows_type( s_height, row_pointer( std::make_shared<Row>( w, c ) ) );
}
Framebuffer::Framebuffer( const Framebuffer &other )
Framebuffer::Framebuffer( const Framebuffer& other )
: rows( other.rows ), icon_name( other.icon_name ), window_title( other.window_title ),
clipboard( other.clipboard ), bell_count( other.bell_count ),
title_initialized( other.title_initialized ), ds( other.ds )
{
}
clipboard( other.clipboard ), bell_count( other.bell_count ), title_initialized( other.title_initialized ),
ds( other.ds )
{}
Framebuffer & Framebuffer::operator=( const Framebuffer &other )
Framebuffer& Framebuffer::operator=( const Framebuffer& other )
{
if ( this != &other ) {
rows = other.rows;
@@ -125,10 +119,14 @@ void DrawState::new_grapheme( void )
void DrawState::snap_cursor_to_border( void )
{
if ( cursor_row < limit_top() ) cursor_row = limit_top();
if ( cursor_row > limit_bottom() ) cursor_row = limit_bottom();
if ( cursor_col < 0 ) cursor_col = 0;
if ( cursor_col >= width ) cursor_col = width - 1;
if ( cursor_row < limit_top() )
cursor_row = limit_top();
if ( cursor_row > limit_bottom() )
cursor_row = limit_bottom();
if ( cursor_col < 0 )
cursor_col = 0;
if ( cursor_col >= width )
cursor_col = width - 1;
}
void DrawState::move_row( int N, bool relative )
@@ -157,7 +155,7 @@ void DrawState::move_col( int N, bool relative, bool implicit )
}
if ( implicit ) {
next_print_will_wrap = (cursor_col >= width);
next_print_will_wrap = ( cursor_col >= width );
}
snap_cursor_to_border();
@@ -170,8 +168,8 @@ void DrawState::move_col( int N, bool relative, bool implicit )
void Framebuffer::move_rows_autoscroll( int rows )
{
/* don't scroll if outside the scrolling region */
if ( (ds.get_cursor_row() < ds.get_scrolling_region_top_row())
|| (ds.get_cursor_row() > ds.get_scrolling_region_bottom_row()) ) {
if ( ( ds.get_cursor_row() < ds.get_scrolling_region_top_row() )
|| ( ds.get_cursor_row() > ds.get_scrolling_region_bottom_row() ) ) {
ds.move_row( rows, true );
return;
}
@@ -189,12 +187,11 @@ void Framebuffer::move_rows_autoscroll( int rows )
ds.move_row( rows, true );
}
Cell *Framebuffer::get_combining_cell( void )
Cell* Framebuffer::get_combining_cell( void )
{
if ( (ds.get_combining_char_col() < 0)
|| (ds.get_combining_char_row() < 0)
|| (ds.get_combining_char_col() >= ds.get_width())
|| (ds.get_combining_char_row() >= ds.get_height()) ) {
if ( ( ds.get_combining_char_col() < 0 ) || ( ds.get_combining_char_row() < 0 )
|| ( ds.get_combining_char_col() >= ds.get_width() )
|| ( ds.get_combining_char_row() >= ds.get_height() ) ) {
return NULL;
} /* can happen if a resize came in between */
@@ -203,26 +200,26 @@ Cell *Framebuffer::get_combining_cell( void )
void DrawState::set_tab( void )
{
tabs[ cursor_col ] = true;
tabs[cursor_col] = true;
}
void DrawState::clear_tab( int col )
{
tabs[ col ] = false;
tabs[col] = false;
}
int DrawState::get_next_tab( int count ) const
{
if ( count >= 0 ) {
for ( int i = cursor_col + 1; i < width; i++ ) {
if ( tabs[ i ] && --count == 0 ) {
if ( tabs[i] && --count == 0 ) {
return i;
}
}
return -1;
}
for ( int i = cursor_col - 1; i > 0; i-- ) {
if ( tabs[ i ] && ++count == 0 ) {
if ( tabs[i] && ++count == 0 ) {
return i;
}
}
@@ -238,8 +235,10 @@ void DrawState::set_scrolling_region( int top, int bottom )
scrolling_region_top_row = top;
scrolling_region_bottom_row = bottom;
if ( scrolling_region_top_row < 0 ) scrolling_region_top_row = 0;
if ( scrolling_region_bottom_row >= height ) scrolling_region_bottom_row = height - 1;
if ( scrolling_region_top_row < 0 )
scrolling_region_top_row = 0;
if ( scrolling_region_bottom_row >= height )
scrolling_region_bottom_row = height - 1;
if ( scrolling_region_bottom_row < scrolling_region_top_row )
scrolling_region_bottom_row = scrolling_region_top_row;
@@ -261,19 +260,16 @@ int DrawState::limit_bottom( void ) const
return origin_mode ? scrolling_region_bottom_row : height - 1;
}
void Framebuffer::apply_renditions_to_cell( Cell *cell )
void Framebuffer::apply_renditions_to_cell( Cell* cell )
{
if (!cell) {
if ( !cell ) {
cell = get_mutable_cell();
}
cell->set_renditions( ds.get_renditions() );
}
SavedCursor::SavedCursor()
: cursor_col( 0 ), cursor_row( 0 ),
renditions( 0 ),
auto_wrap_mode( true ),
origin_mode( false )
: cursor_col( 0 ), cursor_row( 0 ), renditions( 0 ), auto_wrap_mode( true ), origin_mode( false )
{}
void DrawState::save_cursor( void )
@@ -299,8 +295,8 @@ void DrawState::restore_cursor( void )
void Framebuffer::insert_line( int before_row, int count )
{
if ( (before_row < ds.get_scrolling_region_top_row())
|| (before_row > ds.get_scrolling_region_bottom_row() + 1) ) {
if ( ( before_row < ds.get_scrolling_region_top_row() )
|| ( before_row > ds.get_scrolling_region_bottom_row() + 1 ) ) {
return;
}
@@ -318,13 +314,12 @@ void Framebuffer::insert_line( int before_row, int count )
rows.erase( start, start + scroll );
// insert new rows
start = rows.begin() + before_row;
rows.insert( start, scroll, newrow());
rows.insert( start, scroll, newrow() );
}
void Framebuffer::delete_line( int row, int count )
{
if ( (row < ds.get_scrolling_region_top_row())
|| (row > ds.get_scrolling_region_bottom_row()) ) {
if ( ( row < ds.get_scrolling_region_top_row() ) || ( row > ds.get_scrolling_region_bottom_row() ) ) {
return;
}
@@ -342,7 +337,7 @@ void Framebuffer::delete_line( int row, int count )
rows.erase( start, start + scroll );
// insert a block of dummy rows
start = rows.begin() + ds.get_scrolling_region_bottom_row() + 1 - scroll;
rows.insert( start, scroll, newrow());
rows.insert( start, scroll, newrow() );
}
Row::Row( const size_t s_width, const color_type background_color )
@@ -407,26 +402,23 @@ void Framebuffer::resize( int s_width, int s_height )
int oldwidth = ds.get_width();
ds.resize( s_width, s_height );
row_pointer blankrow( newrow());
row_pointer blankrow( newrow() );
if ( oldheight != s_height ) {
rows.resize( s_height, blankrow );
}
if (oldwidth == s_width) {
if ( oldwidth == s_width ) {
return;
}
for ( rows_type::iterator i = rows.begin();
i != rows.end() && *i != blankrow;
i++ ) {
for ( rows_type::iterator i = rows.begin(); i != rows.end() && *i != blankrow; i++ ) {
*i = std::make_shared<Row>( **i );
(*i)->set_wrap( false );
(*i)->cells.resize( s_width, Cell( ds.get_background_rendition() ) );
( *i )->set_wrap( false );
( *i )->cells.resize( s_width, Cell( ds.get_background_rendition() ) );
}
}
void DrawState::resize( int s_width, int s_height )
{
if ( (width != s_width)
|| (height != s_height) ) {
if ( ( width != s_width ) || ( height != s_height ) ) {
/* reset entire scrolling region on any resize */
/* xterm and rxvt-unicode do this. gnome-terminal only
resets scrolling region if it has to become smaller in resize */
@@ -447,15 +439,13 @@ void DrawState::resize( int s_width, int s_height )
/* saved cursor will be snapped to border on restore */
/* invalidate combining char cell if necessary */
if ( (combining_char_col >= width)
|| (combining_char_row >= height) ) {
if ( ( combining_char_col >= width ) || ( combining_char_row >= height ) ) {
combining_char_col = combining_char_row = -1;
}
}
Renditions::Renditions( color_type s_background )
: foreground_color( 0 ), background_color( s_background ),
attributes( 0 )
: foreground_color( 0 ), background_color( s_background ), attributes( 0 )
{}
/* This routine cannot be used to set a color beyond the 16-color set. */
@@ -475,35 +465,54 @@ void Renditions::set_rendition( color_type num )
return;
}
if ( (30 <= num) && (num <= 37) ) { /* foreground color in 8-color set */
if ( ( 30 <= num ) && ( num <= 37 ) ) { /* foreground color in 8-color set */
foreground_color = num;
return;
} else if ( (40 <= num) && (num <= 47) ) { /* background color in 8-color set */
} else if ( ( 40 <= num ) && ( num <= 47 ) ) { /* background color in 8-color set */
background_color = num;
return;
} else if ( (90 <= num) && (num <= 97) ) { /* foreground color in 16-color set */
} else if ( ( 90 <= num ) && ( num <= 97 ) ) { /* foreground color in 16-color set */
foreground_color = num - 90 + 38;
return;
} else if ( (100 <= num) && (num <= 107) ) { /* background color in 16-color set */
} else if ( ( 100 <= num ) && ( num <= 107 ) ) { /* background color in 16-color set */
background_color = num - 100 + 48;
return;
}
bool value = num < 9;
switch ( num ) {
case 1: case 22: set_attribute(bold, value); break;
case 3: case 23: set_attribute(italic, value); break;
case 4: case 24: set_attribute(underlined, value); break;
case 5: case 25: set_attribute(blink, value); break;
case 7: case 27: set_attribute(inverse, value); break;
case 8: case 28: set_attribute(invisible, value); break;
default: break; /* ignore unknown rendition */
case 1:
case 22:
set_attribute( bold, value );
break;
case 3:
case 23:
set_attribute( italic, value );
break;
case 4:
case 24:
set_attribute( underlined, value );
break;
case 5:
case 25:
set_attribute( blink, value );
break;
case 7:
case 27:
set_attribute( inverse, value );
break;
case 8:
case 28:
set_attribute( invisible, value );
break;
default:
break; /* ignore unknown rendition */
}
}
void Renditions::set_foreground_color( int num )
{
if ( (0 <= num) && (num <= 255) ) {
if ( ( 0 <= num ) && ( num <= 255 ) ) {
foreground_color = 30 + num;
} else if ( is_true_color( num ) ) {
foreground_color = num;
@@ -512,7 +521,7 @@ void Renditions::set_foreground_color( int num )
void Renditions::set_background_color( int num )
{
if ( (0 <= num) && (num <= 255) ) {
if ( ( 0 <= num ) && ( num <= 255 ) ) {
background_color = 40 + num;
} else if ( is_true_color( num ) ) {
background_color = num;
@@ -525,12 +534,18 @@ std::string Renditions::sgr( void ) const
char col[64];
ret.append( "\033[0" );
if ( get_attribute( bold ) ) ret.append( ";1" );
if ( get_attribute( italic ) ) ret.append( ";3" );
if ( get_attribute( underlined ) ) ret.append( ";4" );
if ( get_attribute( blink ) ) ret.append( ";5" );
if ( get_attribute( inverse ) ) ret.append( ";7" );
if ( get_attribute( invisible ) ) ret.append( ";8" );
if ( get_attribute( bold ) )
ret.append( ";1" );
if ( get_attribute( italic ) )
ret.append( ";3" );
if ( get_attribute( underlined ) )
ret.append( ";4" );
if ( get_attribute( blink ) )
ret.append( ";5" );
if ( get_attribute( inverse ) )
ret.append( ";7" );
if ( get_attribute( invisible ) )
ret.append( ";8" );
if ( foreground_color ) {
// Since foreground_color is a 25-bit field, it is promoted to an int when
@@ -538,10 +553,12 @@ std::string Renditions::sgr( void ) const
// https://timsong-cpp.github.io/cppwp/n4659/conv.prom#5.) The correct
// printf format specifier is thus %d.
if ( is_true_color( foreground_color ) ) {
snprintf( col, sizeof( col ), ";38;2;%d;%d;%d",
(foreground_color >> 16) & 0xff,
(foreground_color >> 8) & 0xff,
foreground_color & 0xff);
snprintf( col,
sizeof( col ),
";38;2;%d;%d;%d",
( foreground_color >> 16 ) & 0xff,
( foreground_color >> 8 ) & 0xff,
foreground_color & 0xff );
} else if ( foreground_color > 37 ) { /* use 256-color set */
snprintf( col, sizeof( col ), ";38;5;%d", foreground_color - 30 );
} else { /* ANSI foreground color */
@@ -557,10 +574,12 @@ std::string Renditions::sgr( void ) const
if ( background_color ) {
// See comment above about bit-field promotion; it applies here as well.
if ( is_true_color( background_color ) ) {
snprintf( col, sizeof( col ), ";48;2;%d;%d;%d",
(background_color >> 16) & 0xff,
(background_color >> 8) & 0xff,
background_color & 0xff);
snprintf( col,
sizeof( col ),
";48;2;%d;%d;%d",
( background_color >> 16 ) & 0xff,
( background_color >> 8 ) & 0xff,
background_color & 0xff );
} else if ( background_color > 47 ) { /* use 256-color set */
snprintf( col, sizeof( col ), ";48;5;%d", background_color - 40 );
} else { /* ANSI background color */
@@ -578,20 +597,18 @@ std::string Renditions::sgr( void ) const
void Row::reset( color_type background_color )
{
gen = get_gen();
for ( cells_type::iterator i = cells.begin();
i != cells.end();
i++ ) {
for ( cells_type::iterator i = cells.begin(); i != cells.end(); i++ ) {
i->reset( background_color );
}
}
void Framebuffer::prefix_window_title( const title_type &s )
void Framebuffer::prefix_window_title( const title_type& s )
{
if ( icon_name == window_title ) {
/* preserve equivalence */
icon_name.insert(icon_name.begin(), s.begin(), s.end() );
icon_name.insert( icon_name.begin(), s.begin(), s.end() );
}
window_title.insert(window_title.begin(), s.begin(), s.end() );
window_title.insert( window_title.begin(), s.begin(), s.end() );
}
std::string Cell::debug_contents( void ) const
@@ -602,13 +619,11 @@ std::string Cell::debug_contents( void ) const
std::string chars( 1, '\'' );
print_grapheme( chars );
chars.append( "' [" );
const char *lazycomma = "";
const char* lazycomma = "";
char buf[64];
for ( content_type::const_iterator i = contents.begin();
i < contents.end();
i++ ) {
for ( content_type::const_iterator i = contents.begin(); i < contents.end(); i++ ) {
snprintf( buf, sizeof buf, "%s0x%02x", lazycomma, static_cast<uint8_t>(*i) );
snprintf( buf, sizeof buf, "%s0x%02x", lazycomma, static_cast<uint8_t>( *i ) );
chars.append( buf );
lazycomma = ", ";
}
@@ -616,7 +631,7 @@ std::string Cell::debug_contents( void ) const
return chars;
}
bool Cell::compare( const Cell &other ) const
bool Cell::compare( const Cell& other ) const
{
bool ret = false;
@@ -627,13 +642,13 @@ bool Cell::compare( const Cell &other ) const
if ( grapheme != other_grapheme ) {
ret = true;
fprintf( stderr, "Graphemes: '%s' vs. '%s'\n",
grapheme.c_str(), other_grapheme.c_str() );
fprintf( stderr, "Graphemes: '%s' vs. '%s'\n", grapheme.c_str(), other_grapheme.c_str() );
}
if ( !contents_match( other ) ) {
// ret = true;
fprintf( stderr, "Contents: %s (%ld) vs. %s (%ld)\n",
fprintf( stderr,
"Contents: %s (%ld) vs. %s (%ld)\n",
debug_contents().c_str(),
static_cast<long int>( contents.size() ),
other.debug_contents().c_str(),
@@ -646,18 +661,16 @@ bool Cell::compare( const Cell &other ) const
// manipulated. (See [conv.prom] in various C++ standards, e.g.,
// https://timsong-cpp.github.io/cppwp/n4659/conv.prom#5.) The correct
// printf format specifier is thus %d.
fprintf( stderr, "fallback: %d vs. %d\n",
fallback, other.fallback );
fprintf( stderr, "fallback: %d vs. %d\n", fallback, other.fallback );
}
if ( wide != other.wide ) {
ret = true;
// See comment above about bit-field promotion; it applies here as well.
fprintf( stderr, "width: %d vs. %d\n",
wide, other.wide );
fprintf( stderr, "width: %d vs. %d\n", wide, other.wide );
}
if ( !(renditions == other.renditions) ) {
if ( !( renditions == other.renditions ) ) {
ret = true;
fprintf( stderr, "renditions differ\n" );
}
@@ -665,8 +678,7 @@ bool Cell::compare( const Cell &other ) const
if ( wrap != other.wrap ) {
ret = true;
// See comment above about bit-field promotion; it applies here as well.
fprintf( stderr, "wrap: %d vs. %d\n",
wrap, other.wrap );
fprintf( stderr, "wrap: %d vs. %d\n", wrap, other.wrap );
}
return ret;
+119 -105
View File
@@ -45,54 +45,62 @@
/* Terminal framebuffer */
namespace Terminal {
using color_type = uint32_t;
using color_type = uint32_t;
class Renditions {
public:
typedef enum { bold, faint, italic, underlined, blink, inverse, invisible, SIZE } attribute_type;
class Renditions
{
public:
typedef enum
{
bold,
faint,
italic,
underlined,
blink,
inverse,
invisible,
SIZE
} attribute_type;
private:
private:
static const uint64_t true_color_mask = 0x1000000;
uint64_t foreground_color : 25;
uint64_t background_color : 25;
uint64_t attributes : 8;
public:
public:
Renditions( color_type s_background );
void set_foreground_color( int num );
void set_background_color( int num );
void set_rendition( color_type num );
std::string sgr( void ) const;
static unsigned int make_true_color( unsigned int r, unsigned int g, unsigned int b ) {
return true_color_mask | (r << 16) | (g << 8) | b;
static unsigned int make_true_color( unsigned int r, unsigned int g, unsigned int b )
{
return true_color_mask | ( r << 16 ) | ( g << 8 ) | b;
}
static bool is_true_color(unsigned int color) {
return (color & true_color_mask) != 0;
}
static bool is_true_color( unsigned int color ) { return ( color & true_color_mask ) != 0; }
// unsigned int get_foreground_rendition() const { return foreground_color; }
unsigned int get_background_rendition() const { return background_color; }
bool operator==( const Renditions &x ) const
bool operator==( const Renditions& x ) const
{
return ( attributes == x.attributes )
&& ( foreground_color == x.foreground_color )
return ( attributes == x.attributes ) && ( foreground_color == x.foreground_color )
&& ( background_color == x.background_color );
}
void set_attribute( attribute_type attr, bool val )
{
attributes = val ?
( attributes | (1 << attr) ) :
( attributes & ~(1 << attr) );
attributes = val ? ( attributes | ( 1 << attr ) ) : ( attributes & ~( 1 << attr ) );
}
bool get_attribute( attribute_type attr ) const { return attributes & ( 1 << attr ); }
void clear_attributes() { attributes = 0; }
};
};
class Cell {
private:
class Cell
{
private:
typedef std::string content_type; /* can be std::string, std::vector<uint8_t>, or __gnu_cxx::__vstring */
content_type contents;
Renditions renditions;
@@ -100,23 +108,21 @@ namespace Terminal {
unsigned int fallback : 1; /* first character is combining character */
unsigned int wrap : 1;
private:
private:
Cell();
public:
public:
Cell( color_type background_color );
void reset( color_type background_color );
bool operator==( const Cell &x ) const
bool operator==( const Cell& x ) const
{
return ( (contents == x.contents)
&& (fallback == x.fallback)
&& (wide == x.wide)
&& (renditions == x.renditions)
&& (wrap == x.wrap) );
return ( ( contents == x.contents ) && ( fallback == x.fallback ) && ( wide == x.wide )
&& ( renditions == x.renditions ) && ( wrap == x.wrap ) );
}
bool operator!=( const Cell &x ) const { return !operator==( x ); }
bool operator!=( const Cell& x ) const { return !operator==( x ); }
/* Accessors for contents field */
std::string debug_contents( void ) const;
@@ -129,18 +135,15 @@ namespace Terminal {
bool is_blank( void ) const
{
// XXX fix.
return ( contents.empty()
|| contents == " "
|| contents == "\xC2\xA0" );
return ( contents.empty() || contents == " " || contents == "\xC2\xA0" );
}
bool contents_match ( const Cell &other ) const
bool contents_match( const Cell& other ) const
{
return ( is_blank() && other.is_blank() )
|| ( contents == other.contents );
return ( is_blank() && other.is_blank() ) || ( contents == other.contents );
}
bool compare( const Cell &other ) const;
bool compare( const Cell& other ) const;
// Is this a printing ISO 8859-1 character?
static bool isprint_iso8859_1( const wchar_t c )
@@ -148,37 +151,37 @@ namespace Terminal {
return ( c <= 0xff && c >= 0xa0 ) || ( c <= 0x7e && c >= 0x20 );
}
static void append_to_str( std::string &dest, const wchar_t c )
static void append_to_str( std::string& dest, const wchar_t c )
{
/* ASCII? Cheat. */
if ( static_cast<uint32_t>(c) <= 0x7f ) {
dest.push_back( static_cast<char>(c) );
if ( static_cast<uint32_t>( c ) <= 0x7f ) {
dest.push_back( static_cast<char>( c ) );
return;
}
static mbstate_t ps = mbstate_t();
char tmp[MB_LEN_MAX];
size_t ignore = wcrtomb(NULL, 0, &ps);
size_t ignore = wcrtomb( NULL, 0, &ps );
(void)ignore;
size_t len = wcrtomb(tmp, c, &ps);
size_t len = wcrtomb( tmp, c, &ps );
dest.append( tmp, len );
}
void append( const wchar_t c )
{
/* ASCII? Cheat. */
if ( static_cast<uint32_t>(c) <= 0x7f ) {
contents.push_back( static_cast<char>(c) );
if ( static_cast<uint32_t>( c ) <= 0x7f ) {
contents.push_back( static_cast<char>( c ) );
return;
}
static mbstate_t ps = mbstate_t();
char tmp[MB_LEN_MAX];
size_t ignore = wcrtomb(NULL, 0, &ps);
size_t ignore = wcrtomb( NULL, 0, &ps );
(void)ignore;
size_t len = wcrtomb(tmp, c, &ps);
contents.insert( contents.end(), tmp, tmp+len );
size_t len = wcrtomb( tmp, c, &ps );
contents.insert( contents.end(), tmp, tmp + len );
}
void print_grapheme( std::string &output ) const
void print_grapheme( std::string& output ) const
{
if ( contents.empty() ) {
output.append( 1, ' ' );
@@ -205,10 +208,11 @@ namespace Terminal {
void set_fallback( bool f ) { fallback = f; }
bool get_wrap( void ) const { return wrap; }
void set_wrap( bool f ) { wrap = f; }
};
};
class Row {
public:
class Row
{
public:
typedef std::vector<Cell> cells_type;
cells_type cells;
// gen is a generation counter. It can be used to quickly rule
@@ -216,9 +220,10 @@ namespace Terminal {
// in scrolling.
uint64_t gen;
private:
private:
Row();
public:
public:
Row( const size_t s_width, const color_type background_color );
void insert_cell( int col, color_type background_color );
@@ -226,19 +231,17 @@ namespace Terminal {
void reset( color_type background_color );
bool operator==( const Row &x ) const
{
return ( gen == x.gen && cells == x.cells );
}
bool operator==( const Row& x ) const { return ( gen == x.gen && cells == x.cells ); }
bool get_wrap( void ) const { return cells.back().get_wrap(); }
void set_wrap( bool w ) { cells.back().set_wrap( w ); }
uint64_t get_gen() const;
};
};
class SavedCursor {
public:
class SavedCursor
{
public:
int cursor_col, cursor_row;
Renditions renditions;
/* not implemented: character set shift state */
@@ -247,10 +250,11 @@ namespace Terminal {
/* not implemented: state of selective erase */
SavedCursor();
};
};
class DrawState {
private:
class DrawState
{
private:
int width, height;
void new_grapheme( void );
@@ -270,7 +274,7 @@ namespace Terminal {
SavedCursor save;
public:
public:
bool next_print_will_wrap;
bool origin_mode;
bool auto_wrap_mode;
@@ -279,7 +283,8 @@ namespace Terminal {
bool reverse_video;
bool bracketed_paste;
enum MouseReportingMode {
enum MouseReportingMode
{
MOUSE_REPORTING_NONE = 0,
MOUSE_REPORTING_X10 = 9,
MOUSE_REPORTING_VT220 = 1000,
@@ -291,7 +296,8 @@ namespace Terminal {
bool mouse_focus_event; // 1004
bool mouse_alternate_scroll; // 1007
enum MouseEncodingMode {
enum MouseEncodingMode
{
MOUSE_ENCODING_DEFAULT = 0,
MOUSE_ENCODING_UTF8 = 1005,
MOUSE_ENCODING_SGR = 1006,
@@ -341,19 +347,20 @@ namespace Terminal {
DrawState( int s_width, int s_height );
bool operator==( const DrawState &x ) const
bool operator==( const DrawState& x ) const
{
/* only compare fields that affect display */
return ( width == x.width ) && ( height == x.height ) && ( cursor_col == x.cursor_col )
&& ( cursor_row == x.cursor_row ) && ( cursor_visible == x.cursor_visible ) &&
( reverse_video == x.reverse_video ) && ( renditions == x.renditions ) &&
( bracketed_paste == x.bracketed_paste ) && ( mouse_reporting_mode == x.mouse_reporting_mode ) &&
( mouse_focus_event == x.mouse_focus_event ) && ( mouse_alternate_scroll == x.mouse_alternate_scroll) &&
( mouse_encoding_mode == x.mouse_encoding_mode );
&& ( cursor_row == x.cursor_row ) && ( cursor_visible == x.cursor_visible )
&& ( reverse_video == x.reverse_video ) && ( renditions == x.renditions )
&& ( bracketed_paste == x.bracketed_paste ) && ( mouse_reporting_mode == x.mouse_reporting_mode )
&& ( mouse_focus_event == x.mouse_focus_event ) && ( mouse_alternate_scroll == x.mouse_alternate_scroll )
&& ( mouse_encoding_mode == x.mouse_encoding_mode );
}
};
};
class Framebuffer {
class Framebuffer
{
// To minimize copying of rows and cells, we use shared_ptr to
// share unchanged rows between multiple Framebuffers. If we
// write to a row in a Framebuffer and it is shared with other
@@ -366,12 +373,12 @@ namespace Terminal {
// Framebuffers is to simply compare the pointer values. If they
// are equal, then the rows are obviously identical.
// * If no row is shared, the frame has not been modified.
public:
public:
typedef std::vector<wchar_t> title_type;
typedef std::shared_ptr<Row> row_pointer;
typedef std::vector<row_pointer> rows_type; /* can be either std::vector or std::deque */
private:
private:
rows_type rows;
title_type icon_name;
title_type window_title;
@@ -386,54 +393,60 @@ namespace Terminal {
return std::make_shared<Row>( w, c );
}
public:
public:
Framebuffer( int s_width, int s_height );
Framebuffer( const Framebuffer &other );
Framebuffer &operator=( const Framebuffer &other );
Framebuffer( const Framebuffer& other );
Framebuffer& operator=( const Framebuffer& other );
DrawState ds;
const rows_type &get_rows() const { return rows; }
const rows_type& get_rows() const { return rows; }
void scroll( int N );
void move_rows_autoscroll( int rows );
inline const Row *get_row( int row ) const
inline const Row* get_row( int row ) const
{
if ( row == -1 ) row = ds.get_cursor_row();
if ( row == -1 )
row = ds.get_cursor_row();
return rows.at( row ).get();
}
inline const Cell *get_cell( int row = -1, int col = -1 ) const
inline const Cell* get_cell( int row = -1, int col = -1 ) const
{
if ( row == -1 ) row = ds.get_cursor_row();
if ( col == -1 ) col = ds.get_cursor_col();
if ( row == -1 )
row = ds.get_cursor_row();
if ( col == -1 )
col = ds.get_cursor_col();
return &rows.at( row )->cells.at( col );
}
Row *get_mutable_row( int row )
Row* get_mutable_row( int row )
{
if ( row == -1 ) row = ds.get_cursor_row();
row_pointer &mutable_row = rows.at( row );
if ( row == -1 )
row = ds.get_cursor_row();
row_pointer& mutable_row = rows.at( row );
// If the row is shared, copy it.
if (!mutable_row.unique()) {
if ( !mutable_row.unique() ) {
mutable_row = std::make_shared<Row>( *mutable_row );
}
return mutable_row.get();
}
Cell *get_mutable_cell( int row = -1, int col = -1 )
Cell* get_mutable_cell( int row = -1, int col = -1 )
{
if ( row == -1 ) row = ds.get_cursor_row();
if ( col == -1 ) col = ds.get_cursor_col();
if ( row == -1 )
row = ds.get_cursor_row();
if ( col == -1 )
col = ds.get_cursor_col();
return &get_mutable_row( row )->cells.at( col );
}
Cell *get_combining_cell( void );
Cell* get_combining_cell( void );
void apply_renditions_to_cell( Cell *cell );
void apply_renditions_to_cell( Cell* cell );
void insert_line( int before_row, int count );
void delete_line( int row, int count );
@@ -446,28 +459,29 @@ namespace Terminal {
void set_title_initialized( void ) { title_initialized = true; }
bool is_title_initialized( void ) const { return title_initialized; }
void set_icon_name( const title_type &s ) { icon_name = s; }
void set_window_title( const title_type &s ) { window_title = s; }
void set_clipboard( const title_type &s ) { clipboard = s; }
const title_type & get_icon_name( void ) const { return icon_name; }
const title_type & get_window_title( void ) const { return window_title; }
const title_type & get_clipboard( void ) const { return clipboard; }
void set_icon_name( const title_type& s ) { icon_name = s; }
void set_window_title( const title_type& s ) { window_title = s; }
void set_clipboard( const title_type& s ) { clipboard = s; }
const title_type& get_icon_name( void ) const { return icon_name; }
const title_type& get_window_title( void ) const { return window_title; }
const title_type& get_clipboard( void ) const { return clipboard; }
void prefix_window_title( const title_type &s );
void prefix_window_title( const title_type& s );
void resize( int s_width, int s_height );
void reset_cell( Cell *c ) { c->reset( ds.get_background_rendition() ); }
void reset_row( Row *r ) { r->reset( ds.get_background_rendition() ); }
void reset_cell( Cell* c ) { c->reset( ds.get_background_rendition() ); }
void reset_row( Row* r ) { r->reset( ds.get_background_rendition() ); }
void ring_bell( void ) { bell_count++; }
unsigned int get_bell_count( void ) const { return bell_count; }
bool operator==( const Framebuffer &x ) const
bool operator==( const Framebuffer& x ) const
{
return ( rows == x.rows ) && ( window_title == x.window_title ) && ( clipboard == x.clipboard ) && ( bell_count == x.bell_count ) && ( ds == x.ds );
return ( rows == x.rows ) && ( window_title == x.window_title ) && ( clipboard == x.clipboard )
&& ( bell_count == x.bell_count ) && ( ds == x.ds );
}
};
};
}
#endif
+95 -94
View File
@@ -36,15 +36,15 @@
#include <unistd.h>
#include "terminaldispatcher.h"
#include "src/terminal/terminalframebuffer.h"
#include "src/terminal/parseraction.h"
#include "src/terminal/terminalframebuffer.h"
#include "terminaldispatcher.h"
using namespace Terminal;
/* Terminal functions -- routines activated by CSI, escape or a control char */
static void clearline( Framebuffer *fb, int row, int start, int end )
static void clearline( Framebuffer* fb, int row, int start, int end )
{
for ( int col = start; col <= end; col++ ) {
fb->reset_cell( fb->get_mutable_cell( row, col ) );
@@ -52,7 +52,7 @@ static void clearline( Framebuffer *fb, int row, int start, int end )
}
/* erase in line */
static void CSI_EL( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_EL( Framebuffer* fb, Dispatcher* dispatch )
{
switch ( dispatch->getparam( 0, 0 ) ) {
case 0: /* default: active position to end of line, inclusive */
@@ -72,7 +72,8 @@ static void CSI_EL( Framebuffer *fb, Dispatcher *dispatch )
static Function func_CSI_EL( CSI, "K", CSI_EL );
/* erase in display */
static void CSI_ED( Framebuffer *fb, Dispatcher *dispatch ) {
static void CSI_ED( Framebuffer* fb, Dispatcher* dispatch )
{
switch ( dispatch->getparam( 0, 0 ) ) {
case 0: /* active position to end of screen, inclusive */
clearline( fb, -1, fb->ds.get_cursor_col(), fb->ds.get_width() - 1 );
@@ -99,11 +100,11 @@ static void CSI_ED( Framebuffer *fb, Dispatcher *dispatch ) {
static Function func_CSI_ED( CSI, "J", CSI_ED );
/* cursor movement -- relative and absolute */
static void CSI_cursormove( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_cursormove( Framebuffer* fb, Dispatcher* dispatch )
{
int num = dispatch->getparam( 0, 1 );
switch ( dispatch->get_dispatch_chars()[ 0 ] ) {
switch ( dispatch->get_dispatch_chars()[0] ) {
case 'A':
fb->ds.move_row( -num, true );
break;
@@ -134,7 +135,7 @@ static Function func_CSI_cursormove_H( CSI, "H", CSI_cursormove );
static Function func_CSI_cursormove_f( CSI, "f", CSI_cursormove );
/* device attributes */
static void CSI_DA( Framebuffer *fb __attribute((unused)), Dispatcher *dispatch )
static void CSI_DA( Framebuffer* fb __attribute( ( unused ) ), Dispatcher* dispatch )
{
dispatch->terminal_to_host.append( "\033[?62c" ); /* plain vt220 */
}
@@ -142,7 +143,7 @@ static void CSI_DA( Framebuffer *fb __attribute((unused)), Dispatcher *dispatch
static Function func_CSI_DA( CSI, "c", CSI_DA );
/* secondary device attributes */
static void CSI_SDA( Framebuffer *fb __attribute((unused)), Dispatcher *dispatch )
static void CSI_SDA( Framebuffer* fb __attribute( ( unused ) ), Dispatcher* dispatch )
{
dispatch->terminal_to_host.append( "\033[>1;10;0c" ); /* plain vt220 */
}
@@ -150,7 +151,7 @@ static void CSI_SDA( Framebuffer *fb __attribute((unused)), Dispatcher *dispatch
static Function func_CSI_SDA( CSI, ">c", CSI_SDA );
/* screen alignment diagnostic */
static void Esc_DECALN( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
static void Esc_DECALN( Framebuffer* fb, Dispatcher* dispatch __attribute( ( unused ) ) )
{
for ( int y = 0; y < fb->ds.get_height(); y++ ) {
for ( int x = 0; x < fb->ds.get_width(); x++ ) {
@@ -163,7 +164,7 @@ static void Esc_DECALN( Framebuffer *fb, Dispatcher *dispatch __attribute((unuse
static Function func_Esc_DECALN( ESCAPE, "#8", Esc_DECALN );
/* line feed */
static void Ctrl_LF( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
static void Ctrl_LF( Framebuffer* fb, Dispatcher* dispatch __attribute( ( unused ) ) )
{
fb->move_rows_autoscroll( 1 );
}
@@ -175,7 +176,7 @@ static Function func_Ctrl_VT( CONTROL, "\x0b", Ctrl_LF );
static Function func_Ctrl_FF( CONTROL, "\x0c", Ctrl_LF );
/* carriage return */
static void Ctrl_CR( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
static void Ctrl_CR( Framebuffer* fb, Dispatcher* dispatch __attribute( ( unused ) ) )
{
fb->ds.move_col( 0 );
}
@@ -183,7 +184,7 @@ static void Ctrl_CR( Framebuffer *fb, Dispatcher *dispatch __attribute((unused))
static Function func_Ctrl_CR( CONTROL, "\x0d", Ctrl_CR );
/* backspace */
static void Ctrl_BS( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
static void Ctrl_BS( Framebuffer* fb, Dispatcher* dispatch __attribute( ( unused ) ) )
{
fb->ds.move_col( -1, true );
}
@@ -191,7 +192,7 @@ static void Ctrl_BS( Framebuffer *fb, Dispatcher *dispatch __attribute((unused))
static Function func_Ctrl_BS( CONTROL, "\x08", Ctrl_BS );
/* reverse index -- like a backwards line feed */
static void Ctrl_RI( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
static void Ctrl_RI( Framebuffer* fb, Dispatcher* dispatch __attribute( ( unused ) ) )
{
fb->move_rows_autoscroll( -1 );
}
@@ -199,7 +200,7 @@ static void Ctrl_RI( Framebuffer *fb, Dispatcher *dispatch __attribute((unused))
static Function func_Ctrl_RI( CONTROL, "\x8D", Ctrl_RI );
/* newline */
static void Ctrl_NEL( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
static void Ctrl_NEL( Framebuffer* fb, Dispatcher* dispatch __attribute( ( unused ) ) )
{
fb->ds.move_col( 0 );
fb->move_rows_autoscroll( 1 );
@@ -208,7 +209,7 @@ static void Ctrl_NEL( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)
static Function func_Ctrl_NEL( CONTROL, "\x85", Ctrl_NEL );
/* horizontal tab */
static void HT_n( Framebuffer *fb, size_t count )
static void HT_n( Framebuffer* fb, size_t count )
{
int col = fb->ds.get_next_tab( count );
if ( col == -1 ) { /* no tabs, go to end of line */
@@ -223,16 +224,16 @@ static void HT_n( Framebuffer *fb, size_t count )
fb->ds.next_print_will_wrap = wrap_state_save;
}
static void Ctrl_HT( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
static void Ctrl_HT( Framebuffer* fb, Dispatcher* dispatch __attribute( ( unused ) ) )
{
HT_n( fb, 1 );
}
static Function func_Ctrl_HT( CONTROL, "\x09", Ctrl_HT, false );
static void CSI_CxT( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_CxT( Framebuffer* fb, Dispatcher* dispatch )
{
int param = dispatch->getparam( 0, 1 );
if ( dispatch->get_dispatch_chars()[ 0 ] == 'Z' ) {
if ( dispatch->get_dispatch_chars()[0] == 'Z' ) {
param = -param;
}
if ( param == 0 ) {
@@ -245,7 +246,7 @@ static Function func_CSI_CHT( CSI, "I", CSI_CxT, false );
static Function func_CSI_CBT( CSI, "Z", CSI_CxT, false );
/* horizontal tab set */
static void Ctrl_HTS( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
static void Ctrl_HTS( Framebuffer* fb, Dispatcher* dispatch __attribute( ( unused ) ) )
{
fb->ds.set_tab();
}
@@ -253,7 +254,7 @@ static void Ctrl_HTS( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)
static Function func_Ctrl_HTS( CONTROL, "\x88", Ctrl_HTS );
/* tabulation clear */
static void CSI_TBC( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_TBC( Framebuffer* fb, Dispatcher* dispatch )
{
int param = dispatch->getparam( 0, 0 );
switch ( param ) {
@@ -274,10 +275,11 @@ static void CSI_TBC( Framebuffer *fb, Dispatcher *dispatch )
/* TBC preserves wrap state */
static Function func_CSI_TBC( CSI, "g", CSI_TBC, false );
static bool *get_DEC_mode( int param, Framebuffer *fb ) {
static bool* get_DEC_mode( int param, Framebuffer* fb )
{
switch ( param ) {
case 1: /* cursor key mode */
return &(fb->ds.application_mode_cursor_keys);
return &( fb->ds.application_mode_cursor_keys );
case 3: /* 80/132. Ignore but clear screen. */
/* clear screen */
fb->ds.move_row( 0 );
@@ -287,21 +289,21 @@ static bool *get_DEC_mode( int param, Framebuffer *fb ) {
}
return NULL;
case 5: /* reverse video */
return &(fb->ds.reverse_video);
return &( fb->ds.reverse_video );
case 6: /* origin */
fb->ds.move_row( 0 );
fb->ds.move_col( 0 );
return &(fb->ds.origin_mode);
return &( fb->ds.origin_mode );
case 7: /* auto wrap */
return &(fb->ds.auto_wrap_mode);
return &( fb->ds.auto_wrap_mode );
case 25:
return &(fb->ds.cursor_visible);
return &( fb->ds.cursor_visible );
case 1004: /* xterm mouse focus event */
return &(fb->ds.mouse_focus_event);
return &( fb->ds.mouse_focus_event );
case 1007: /* xterm mouse alternate scroll */
return &(fb->ds.mouse_alternate_scroll);
return &( fb->ds.mouse_alternate_scroll );
case 2004: /* bracketed paste */
return &(fb->ds.bracketed_paste);
return &( fb->ds.bracketed_paste );
default:
break;
}
@@ -309,20 +311,22 @@ static bool *get_DEC_mode( int param, Framebuffer *fb ) {
}
/* helper for CSI_DECSM and CSI_DECRM */
static void set_if_available( bool *mode, bool value )
static void set_if_available( bool* mode, bool value )
{
if ( mode ) { *mode = value; }
if ( mode ) {
*mode = value;
}
}
/* set private mode */
static void CSI_DECSM( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_DECSM( Framebuffer* fb, Dispatcher* dispatch )
{
for ( int i = 0; i < dispatch->param_count(); i++ ) {
int param = dispatch->getparam( i, 0 );
if (param == 9 || (param >= 1000 && param <= 1003)) {
fb->ds.mouse_reporting_mode = (Terminal::DrawState::MouseReportingMode) param;
} else if (param == 1005 || param == 1006 || param == 1015) {
fb->ds.mouse_encoding_mode = (Terminal::DrawState::MouseEncodingMode) param;
if ( param == 9 || ( param >= 1000 && param <= 1003 ) ) {
fb->ds.mouse_reporting_mode = (Terminal::DrawState::MouseReportingMode)param;
} else if ( param == 1005 || param == 1006 || param == 1015 ) {
fb->ds.mouse_encoding_mode = (Terminal::DrawState::MouseEncodingMode)param;
} else {
set_if_available( get_DEC_mode( param, fb ), true );
}
@@ -330,13 +334,13 @@ static void CSI_DECSM( Framebuffer *fb, Dispatcher *dispatch )
}
/* clear private mode */
static void CSI_DECRM( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_DECRM( Framebuffer* fb, Dispatcher* dispatch )
{
for ( int i = 0; i < dispatch->param_count(); i++ ) {
int param = dispatch->getparam( i, 0 );
if (param == 9 || (param >= 1000 && param <= 1003)) {
if ( param == 9 || ( param >= 1000 && param <= 1003 ) ) {
fb->ds.mouse_reporting_mode = Terminal::DrawState::MOUSE_REPORTING_NONE;
} else if (param == 1005 || param == 1006 || param == 1015) {
} else if ( param == 1005 || param == 1006 || param == 1015 ) {
fb->ds.mouse_encoding_mode = Terminal::DrawState::MOUSE_ENCODING_DEFAULT;
} else {
set_if_available( get_DEC_mode( param, fb ), false );
@@ -348,18 +352,19 @@ static void CSI_DECRM( Framebuffer *fb, Dispatcher *dispatch )
static Function func_CSI_DECSM( CSI, "?h", CSI_DECSM, false );
static Function func_CSI_DECRM( CSI, "?l", CSI_DECRM, false );
static bool *get_ANSI_mode( int param, Framebuffer *fb ) {
static bool* get_ANSI_mode( int param, Framebuffer* fb )
{
if ( param == 4 ) { /* insert/replace mode */
return &(fb->ds.insert_mode);
return &( fb->ds.insert_mode );
}
return NULL;
}
/* set mode */
static void CSI_SM( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_SM( Framebuffer* fb, Dispatcher* dispatch )
{
for ( int i = 0; i < dispatch->param_count(); i++ ) {
bool *mode = get_ANSI_mode( dispatch->getparam( i, 0 ), fb );
bool* mode = get_ANSI_mode( dispatch->getparam( i, 0 ), fb );
if ( mode ) {
*mode = true;
}
@@ -367,10 +372,10 @@ static void CSI_SM( Framebuffer *fb, Dispatcher *dispatch )
}
/* clear mode */
static void CSI_RM( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_RM( Framebuffer* fb, Dispatcher* dispatch )
{
for ( int i = 0; i < dispatch->param_count(); i++ ) {
bool *mode = get_ANSI_mode( dispatch->getparam( i, 0 ), fb );
bool* mode = get_ANSI_mode( dispatch->getparam( i, 0 ), fb );
if ( mode ) {
*mode = false;
}
@@ -381,14 +386,12 @@ static Function func_CSI_SM( CSI, "h", CSI_SM );
static Function func_CSI_RM( CSI, "l", CSI_RM );
/* set top and bottom margins */
static void CSI_DECSTBM( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_DECSTBM( Framebuffer* fb, Dispatcher* dispatch )
{
int top = dispatch->getparam( 0, 1 );
int bottom = dispatch->getparam( 1, fb->ds.get_height() );
if ( (bottom <= top)
|| (top > fb->ds.get_height())
|| (top == 0 && bottom == 1) ) {
if ( ( bottom <= top ) || ( top > fb->ds.get_height() ) || ( top == 0 && bottom == 1 ) ) {
return; /* invalid, xterm ignores */
}
@@ -400,14 +403,15 @@ static void CSI_DECSTBM( Framebuffer *fb, Dispatcher *dispatch )
static Function func_CSI_DECSTMB( CSI, "r", CSI_DECSTBM );
/* terminal bell */
static void Ctrl_BEL( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) ) {
static void Ctrl_BEL( Framebuffer* fb, Dispatcher* dispatch __attribute( ( unused ) ) )
{
fb->ring_bell();
}
static Function func_Ctrl_BEL( CONTROL, "\x07", Ctrl_BEL );
/* select graphics rendition -- e.g., bold, blinking, etc. */
static void CSI_SGR( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_SGR( Framebuffer* fb, Dispatcher* dispatch )
{
for ( int i = 0; i < dispatch->param_count(); i++ ) {
int rendition = dispatch->getparam( i, 0 );
@@ -415,23 +419,20 @@ static void CSI_SGR( Framebuffer *fb, Dispatcher *dispatch )
because Ps of 0 in that case does not mean reset to default, even
though it means that otherwise (as usually renditions are applied
in order). */
if ((rendition == 38 || rendition == 48) &&
(dispatch->param_count() - i >= 3) &&
(dispatch->getparam( i+1, -1 ) == 5)) {
(rendition == 38) ?
fb->ds.set_foreground_color( dispatch->getparam( i+2, 0 ) ) :
fb->ds.set_background_color( dispatch->getparam( i+2, 0 ) );
if ( ( rendition == 38 || rendition == 48 ) && ( dispatch->param_count() - i >= 3 )
&& ( dispatch->getparam( i + 1, -1 ) == 5 ) ) {
( rendition == 38 ) ? fb->ds.set_foreground_color( dispatch->getparam( i + 2, 0 ) )
: fb->ds.set_background_color( dispatch->getparam( i + 2, 0 ) );
i += 2;
continue;
}
/* True color support: ESC[ ... [34]8;2;<r>;<g>;<b> ... m */
if ( (rendition == 38 || rendition == 48) &&
(dispatch->param_count() - i >= 5) &&
(dispatch->getparam( i+1, -1 ) == 2)) {
unsigned int red = dispatch->getparam(i+2, 0);
unsigned int green = dispatch->getparam(i+3, 0);
unsigned int blue = dispatch->getparam(i+4, 0);
if ( ( rendition == 38 || rendition == 48 ) && ( dispatch->param_count() - i >= 5 )
&& ( dispatch->getparam( i + 1, -1 ) == 2 ) ) {
unsigned int red = dispatch->getparam( i + 2, 0 );
unsigned int green = dispatch->getparam( i + 3, 0 );
unsigned int blue = dispatch->getparam( i + 4, 0 );
unsigned int color;
color = Renditions::make_true_color( red, green, blue );
@@ -452,12 +453,12 @@ static void CSI_SGR( Framebuffer *fb, Dispatcher *dispatch )
static Function func_CSI_SGR( CSI, "m", CSI_SGR, false ); /* changing renditions doesn't clear wrap flag */
/* save and restore cursor */
static void Esc_DECSC( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
static void Esc_DECSC( Framebuffer* fb, Dispatcher* dispatch __attribute( ( unused ) ) )
{
fb->ds.save_cursor();
}
static void Esc_DECRC( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
static void Esc_DECRC( Framebuffer* fb, Dispatcher* dispatch __attribute( ( unused ) ) )
{
fb->ds.restore_cursor();
}
@@ -466,7 +467,7 @@ static Function func_Esc_DECSC( ESCAPE, "7", Esc_DECSC );
static Function func_Esc_DECRC( ESCAPE, "8", Esc_DECRC );
/* device status report -- e.g., cursor position (used by resize) */
static void CSI_DSR( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_DSR( Framebuffer* fb, Dispatcher* dispatch )
{
int param = dispatch->getparam( 0, 0 );
@@ -475,10 +476,8 @@ static void CSI_DSR( Framebuffer *fb, Dispatcher *dispatch )
dispatch->terminal_to_host.append( "\033[0n" );
break;
case 6: /* report of active position requested */
char cpr[ 32 ];
snprintf( cpr, 32, "\033[%d;%dR",
fb->ds.get_cursor_row() + 1,
fb->ds.get_cursor_col() + 1 );
char cpr[32];
snprintf( cpr, 32, "\033[%d;%dR", fb->ds.get_cursor_row() + 1, fb->ds.get_cursor_col() + 1 );
dispatch->terminal_to_host.append( cpr );
break;
default:
@@ -489,7 +488,7 @@ static void CSI_DSR( Framebuffer *fb, Dispatcher *dispatch )
static Function func_CSI_DSR( CSI, "n", CSI_DSR );
/* insert line */
static void CSI_IL( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_IL( Framebuffer* fb, Dispatcher* dispatch )
{
int lines = dispatch->getparam( 0, 1 );
@@ -503,7 +502,7 @@ static void CSI_IL( Framebuffer *fb, Dispatcher *dispatch )
static Function func_CSI_IL( CSI, "L", CSI_IL );
/* delete line */
static void CSI_DL( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_DL( Framebuffer* fb, Dispatcher* dispatch )
{
int lines = dispatch->getparam( 0, 1 );
@@ -517,7 +516,7 @@ static void CSI_DL( Framebuffer *fb, Dispatcher *dispatch )
static Function func_CSI_DL( CSI, "M", CSI_DL );
/* insert characters */
static void CSI_ICH( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_ICH( Framebuffer* fb, Dispatcher* dispatch )
{
int cells = dispatch->getparam( 0, 1 );
@@ -529,7 +528,7 @@ static void CSI_ICH( Framebuffer *fb, Dispatcher *dispatch )
static Function func_CSI_ICH( CSI, "@", CSI_ICH );
/* delete character */
static void CSI_DCH( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_DCH( Framebuffer* fb, Dispatcher* dispatch )
{
int cells = dispatch->getparam( 0, 1 );
@@ -541,7 +540,7 @@ static void CSI_DCH( Framebuffer *fb, Dispatcher *dispatch )
static Function func_CSI_DCH( CSI, "P", CSI_DCH );
/* line position absolute */
static void CSI_VPA( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_VPA( Framebuffer* fb, Dispatcher* dispatch )
{
int row = dispatch->getparam( 0, 1 );
fb->ds.move_row( row - 1 );
@@ -550,7 +549,7 @@ static void CSI_VPA( Framebuffer *fb, Dispatcher *dispatch )
static Function func_CSI_VPA( CSI, "d", CSI_VPA );
/* character position absolute */
static void CSI_HPA( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_HPA( Framebuffer* fb, Dispatcher* dispatch )
{
int col = dispatch->getparam( 0, 1 );
fb->ds.move_col( col - 1 );
@@ -560,7 +559,7 @@ static Function func_CSI_CHA( CSI, "G", CSI_HPA ); /* ECMA-48 name: CHA */
static Function func_CSI_HPA( CSI, "\x60", CSI_HPA ); /* ECMA-48 name: HPA */
/* erase character */
static void CSI_ECH( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_ECH( Framebuffer* fb, Dispatcher* dispatch )
{
int num = dispatch->getparam( 0, 1 );
int limit = fb->ds.get_cursor_col() + num - 1;
@@ -574,7 +573,7 @@ static void CSI_ECH( Framebuffer *fb, Dispatcher *dispatch )
static Function func_CSI_ECH( CSI, "X", CSI_ECH );
/* reset to initial state */
static void Esc_RIS( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
static void Esc_RIS( Framebuffer* fb, Dispatcher* dispatch __attribute( ( unused ) ) )
{
fb->reset();
}
@@ -582,7 +581,7 @@ static void Esc_RIS( Framebuffer *fb, Dispatcher *dispatch __attribute((unused))
static Function func_Esc_RIS( ESCAPE, "c", Esc_RIS );
/* soft reset */
static void CSI_DECSTR( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
static void CSI_DECSTR( Framebuffer* fb, Dispatcher* dispatch __attribute( ( unused ) ) )
{
fb->soft_reset();
}
@@ -590,45 +589,47 @@ static void CSI_DECSTR( Framebuffer *fb, Dispatcher *dispatch __attribute((unuse
static Function func_CSI_DECSTR( CSI, "!p", CSI_DECSTR );
/* xterm uses an Operating System Command to set the window title */
void Dispatcher::OSC_dispatch( const Parser::OSC_End *act __attribute((unused)), Framebuffer *fb )
void Dispatcher::OSC_dispatch( const Parser::OSC_End* act __attribute( ( unused ) ), Framebuffer* fb )
{
/* handle osc copy clipboard sequence 52;c; */
if ( OSC_string.size() >= 5 && OSC_string[ 0 ] == L'5' &&
OSC_string[ 1 ] == L'2' && OSC_string[ 2 ] == L';' &&
OSC_string[ 3 ] == L'c' && OSC_string[ 4 ] == L';') {
Terminal::Framebuffer::title_type clipboard(
OSC_string.begin() + 5, OSC_string.end() );
if ( OSC_string.size() >= 5 && OSC_string[0] == L'5' && OSC_string[1] == L'2' && OSC_string[2] == L';'
&& OSC_string[3] == L'c' && OSC_string[4] == L';' ) {
Terminal::Framebuffer::title_type clipboard( OSC_string.begin() + 5, OSC_string.end() );
fb->set_clipboard( clipboard );
/* handle osc terminal title sequence */
} else if ( OSC_string.size() >= 1 ) {
long cmd_num = -1;
int offset = 0;
if ( OSC_string[ 0 ] == L';' ) {
if ( OSC_string[0] == L';' ) {
/* OSC of the form "\033];<title>\007" */
cmd_num = 0; /* treat it as as a zero */
offset = 1;
} else if ( (OSC_string.size() >= 2) && (OSC_string[ 1 ] == L';') ) {
} else if ( ( OSC_string.size() >= 2 ) && ( OSC_string[1] == L';' ) ) {
/* OSC of the form "\033]X;<title>\007" where X can be:
* 0: set icon name and window title
* 1: set icon name
* 2: set window title */
cmd_num = OSC_string[ 0 ] - L'0';
cmd_num = OSC_string[0] - L'0';
offset = 2;
}
bool set_icon = cmd_num == 0 || cmd_num == 1;
bool set_title = cmd_num == 0 || cmd_num == 2;
if ( set_icon || set_title ) {
fb->set_title_initialized();
int title_length = std::min(OSC_string.size(), (size_t)256);
int title_length = std::min( OSC_string.size(), (size_t)256 );
Terminal::Framebuffer::title_type newtitle( OSC_string.begin() + offset, OSC_string.begin() + title_length );
if ( set_icon ) { fb->set_icon_name( newtitle ); }
if ( set_title ) { fb->set_window_title( newtitle ); }
if ( set_icon ) {
fb->set_icon_name( newtitle );
}
if ( set_title ) {
fb->set_window_title( newtitle );
}
}
}
}
/* scroll down or terminfo indn */
static void CSI_SD( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_SD( Framebuffer* fb, Dispatcher* dispatch )
{
fb->scroll( dispatch->getparam( 0, 1 ) );
}
@@ -636,7 +637,7 @@ static void CSI_SD( Framebuffer *fb, Dispatcher *dispatch )
static Function func_CSI_SD( CSI, "S", CSI_SD );
/* scroll up or terminfo rin */
static void CSI_SU( Framebuffer *fb, Dispatcher *dispatch )
static void CSI_SU( Framebuffer* fb, Dispatcher* dispatch )
{
fb->scroll( -dispatch->getparam( 0, 1 ) );
}
+4 -7
View File
@@ -36,8 +36,7 @@
using namespace Terminal;
std::string UserInput::input( const Parser::UserByte *act,
bool application_mode_cursor_keys )
std::string UserInput::input( const Parser::UserByte* act, bool application_mode_cursor_keys )
{
/* The user will always be in application mode. If stm is not in
application mode, convert user's cursor control function to an
@@ -66,13 +65,11 @@ std::string UserInput::input( const Parser::UserByte *act,
case SS3:
state = Ground;
if ( (!application_mode_cursor_keys)
&& (act->c >= 'A')
&& (act->c <= 'D') ) {
char translated_cursor[ 2 ] = { '[', act->c };
if ( ( !application_mode_cursor_keys ) && ( act->c >= 'A' ) && ( act->c <= 'D' ) ) {
char translated_cursor[2] = { '[', act->c };
return std::string( translated_cursor, 2 );
} else {
char original_cursor[ 2 ] = { 'O', act->c };
char original_cursor[2] = { 'O', act->c };
return std::string( original_cursor, 2 );
}
+12 -13
View File
@@ -33,31 +33,30 @@
#ifndef TERMINALUSERINPUT_HPP
#define TERMINALUSERINPUT_HPP
#include <string>
#include "src/terminal/parseraction.h"
#include <string>
namespace Terminal {
class UserInput {
public:
enum UserInputState {
class UserInput
{
public:
enum UserInputState
{
Ground,
ESC,
SS3
};
private:
private:
UserInputState state;
public:
UserInput()
: state( Ground )
{}
public:
UserInput() : state( Ground ) {}
std::string input( const Parser::UserByte *act,
bool application_mode_cursor_keys );
std::string input( const Parser::UserByte* act, bool application_mode_cursor_keys );
bool operator==( const UserInput &x ) const { return state == x.state; }
};
bool operator==( const UserInput& x ) const { return state == x.state; }
};
}
#endif
+25 -24
View File
@@ -38,11 +38,11 @@
the Mosh project. */
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include <cstring>
#include "src/crypto/base64.h"
#include "base64_vector.h"
#include "src/crypto/base64.h"
#include "src/crypto/crypto.h"
#include "src/crypto/prng.h"
#include "src/util/fatal_assert.h"
@@ -54,38 +54,39 @@
bool verbose = false;
static void test_base64( void ) {
static void test_base64( void )
{
/* run through a test vector */
char encoded[25];
uint8_t decoded[16];
size_t b64_len = 24;
size_t raw_len = 16;
for ( base64_test_row *row = static_base64_vector; *row->native != '\0'; row++ ) {
memset(encoded, '\0', sizeof encoded);
memset(decoded, '\0', sizeof decoded);
for ( base64_test_row* row = static_base64_vector; *row->native != '\0'; row++ ) {
memset( encoded, '\0', sizeof encoded );
memset( decoded, '\0', sizeof decoded );
base64_encode(static_cast<const uint8_t *>(row->native), raw_len, encoded, b64_len);
base64_encode( static_cast<const uint8_t*>( row->native ), raw_len, encoded, b64_len );
fatal_assert( b64_len == 24 );
fatal_assert( !memcmp(row->encoded, encoded, sizeof encoded));
fatal_assert( !memcmp( row->encoded, encoded, sizeof encoded ) );
fatal_assert( base64_decode(row->encoded, b64_len, decoded, &raw_len ));
fatal_assert( base64_decode( row->encoded, b64_len, decoded, &raw_len ) );
fatal_assert( raw_len == 16 );
fatal_assert( !memcmp(row->native, decoded, sizeof decoded));
fatal_assert( !memcmp( row->native, decoded, sizeof decoded ) );
}
if ( verbose ) {
printf( "validation PASSED\n" );
}
/* try 0..255 in the last byte; make sure the final two characters are output properly */
uint8_t source[16];
memset(source, '\0', sizeof source);
memset( source, '\0', sizeof source );
for ( int i = 0; i < 256; i++ ) {
source[15] = i;
base64_encode(source, raw_len, encoded, b64_len);
base64_encode( source, raw_len, encoded, b64_len );
fatal_assert( b64_len == 24 );
fatal_assert( base64_decode(encoded, b64_len, decoded, &raw_len ));
fatal_assert( base64_decode( encoded, b64_len, decoded, &raw_len ) );
fatal_assert( raw_len == 16 );
fatal_assert( !memcmp(source, decoded, sizeof decoded));
fatal_assert( !memcmp( source, decoded, sizeof decoded ) );
}
if ( verbose ) {
printf( "last-byte PASSED\n" );
@@ -93,17 +94,17 @@ static void test_base64( void ) {
/* randomly try keys */
PRNG prng;
for ( int i = 0; i < ( 1<<17 ); i++ ) {
Base64Key key1(prng);
Base64Key key2(key1.printable_key());
fatal_assert( key1.printable_key() == key2.printable_key() && !memcmp(key1.data(), key2.data(), 16 ));
for ( int i = 0; i < ( 1 << 17 ); i++ ) {
Base64Key key1( prng );
Base64Key key2( key1.printable_key() );
fatal_assert( key1.printable_key() == key2.printable_key() && !memcmp( key1.data(), key2.data(), 16 ) );
}
if ( verbose ) {
printf( "random PASSED\n" );
}
/* test bad keys */
const char *bad_keys[] = {
const char* bad_keys[] = {
"",
"AAAAAAAAAAAAAAAAAAAAAA",
"AAAAAAAAAAAAAAAAAAAAAA=",
@@ -119,25 +120,25 @@ static void test_base64( void ) {
"AAAAAAAAAA==",
NULL,
};
for ( const char **key = bad_keys; *key != NULL; key++ ) {
for ( const char** key = bad_keys; *key != NULL; key++ ) {
b64_len = 24;
raw_len = 16;
fatal_assert( !base64_decode(*key, b64_len, decoded, &raw_len ));
fatal_assert( !base64_decode( *key, b64_len, decoded, &raw_len ) );
}
if ( verbose ) {
printf( "bad-keys PASSED\n" );
}
}
int main( int argc, char *argv[] )
int main( int argc, char* argv[] )
{
if ( argc >= 2 && strcmp( argv[ 1 ], "-v" ) == 0 ) {
if ( argc >= 2 && strcmp( argv[1], "-v" ) == 0 ) {
verbose = true;
}
try {
test_base64();
} catch ( const std::exception &e ) {
} catch ( const std::exception& e ) {
fprintf( stderr, "Error: %s\r\n", e.what() );
return 1;
}
+6 -2
View File
@@ -1,3 +1,7 @@
struct base64_test_row { const unsigned char native[17]; const char encoded[25]; };
typedef base64_test_row *base64_test_vector;
struct base64_test_row
{
const unsigned char native[17];
const char encoded[25];
};
typedef base64_test_row* base64_test_vector;
extern base64_test_row static_base64_vector[];
+18 -15
View File
@@ -48,7 +48,7 @@ using namespace Crypto;
PRNG prng;
const size_t MESSAGE_SIZE_MAX = (2048 - 16);
const size_t MESSAGE_SIZE_MAX = ( 2048 - 16 );
const size_t MESSAGES_PER_SESSION = 256;
const size_t NUM_SESSIONS = 64;
@@ -56,27 +56,29 @@ bool verbose = false;
#define NONCE_FMT "%016" PRIx64
static std::string random_payload( void ) {
static std::string random_payload( void )
{
const size_t len = prng.uint32() % MESSAGE_SIZE_MAX;
char buf[ MESSAGE_SIZE_MAX ];
char buf[MESSAGE_SIZE_MAX];
prng.fill( buf, len );
std::string payload( buf, len );
return payload;
}
static void test_bad_decrypt( Session &decryption_session ) {
static void test_bad_decrypt( Session& decryption_session )
{
std::string bad_ct = random_payload();
bool got_exn = false;
try {
decryption_session.decrypt( bad_ct );
} catch ( const CryptoException &e ) {
} catch ( const CryptoException& e ) {
got_exn = true;
/* The "bad decrypt" exception needs to be non-fatal, otherwise we are
vulnerable to an easy DoS. */
fatal_assert( ! e.fatal );
fatal_assert( !e.fatal );
}
if ( verbose ) {
@@ -86,7 +88,8 @@ static void test_bad_decrypt( Session &decryption_session ) {
}
/* Generate a single key and initial nonce, then perform some encryptions. */
static void test_one_session( void ) {
static void test_one_session( void )
{
Base64Key key;
Session encryption_session( key );
Session decryption_session( key );
@@ -97,7 +100,7 @@ static void test_one_session( void ) {
hexdump( key.data(), 16, "key" );
}
for ( size_t i=0; i<MESSAGES_PER_SESSION; i++ ) {
for ( size_t i = 0; i < MESSAGES_PER_SESSION; i++ ) {
Nonce nonce( nonce_int );
fatal_assert( nonce.val() == nonce_int );
@@ -123,7 +126,7 @@ static void test_one_session( void ) {
nonce_int++;
if ( ! ( prng.uint8() % 16 ) ) {
if ( !( prng.uint8() % 16 ) ) {
test_bad_decrypt( decryption_session );
}
@@ -133,17 +136,17 @@ static void test_one_session( void ) {
}
}
int main( int argc, char *argv[] ) {
if ( argc >= 2 && strcmp( argv[ 1 ], "-v" ) == 0 ) {
int main( int argc, char* argv[] )
{
if ( argc >= 2 && strcmp( argv[1], "-v" ) == 0 ) {
verbose = true;
}
for ( size_t i=0; i<NUM_SESSIONS; i++ ) {
for ( size_t i = 0; i < NUM_SESSIONS; i++ ) {
try {
test_one_session();
} catch ( const CryptoException &e ) {
fprintf( stderr, "Crypto exception: %s\r\n",
e.what() );
} catch ( const CryptoException& e ) {
fprintf( stderr, "Crypto exception: %s\r\n", e.what() );
return 1;
}
}
+4 -4
View File
@@ -56,9 +56,9 @@
#include "src/util/pty_compat.h"
#include "src/util/swrite.h"
int main( int argc, char *argv[] )
int main( int argc, char* argv[] )
{
if (argc < 2) {
if ( argc < 2 ) {
fprintf( stderr, "usage: inpty COMMAND [ARGS...]\n" );
return 1;
}
@@ -68,7 +68,7 @@ int main( int argc, char *argv[] )
winsize.ws_col = 80;
winsize.ws_row = 24;
int saved_stderr = dup(STDERR_FILENO);
int saved_stderr = dup( STDERR_FILENO );
if ( saved_stderr < 0 ) {
perror( "dup" );
return 1;
@@ -101,7 +101,7 @@ int main( int argc, char *argv[] )
}
while ( 1 ) {
char buf[ 1024 ];
char buf[1024];
ssize_t bytes_read = read( master, buf, sizeof( buf ) );
if ( bytes_read == 0 || ( bytes_read < 0 && errno == EIO ) ) { /* EOF */
break;
+1 -1
View File
@@ -34,7 +34,7 @@
#include "src/util/locale_utils.h"
int main( int argc __attribute__(( unused )), char **argv __attribute__(( unused )))
int main( int argc __attribute__( ( unused ) ), char** argv __attribute__( ( unused ) ) )
{
set_native_locale();
if ( !is_utf8_locale() ) {
+1 -1
View File
@@ -32,8 +32,8 @@
/* Tests that the Mosh network layer seems to be using unique nonces */
#include <iostream>
#include <cstdlib>
#include <iostream>
#include <set>
#include "src/network/network.h"
+205 -181
View File
@@ -56,41 +56,50 @@ using Crypto::AlignedBuffer;
bool verbose = false;
static bool equal( const AlignedBuffer &a, const AlignedBuffer &b ) {
return ( a.len() == b.len() )
&& !memcmp( a.data(), b.data(), a.len() );
static bool equal( const AlignedBuffer& a, const AlignedBuffer& b )
{
return ( a.len() == b.len() ) && !memcmp( a.data(), b.data(), a.len() );
}
using AlignedPointer = std::shared_ptr<AlignedBuffer>;
static AlignedBuffer *get_ctx( const AlignedBuffer &key ) {
AlignedBuffer *ctx_buf = new AlignedBuffer( ae_ctx_sizeof() );
static AlignedBuffer* get_ctx( const AlignedBuffer& key )
{
AlignedBuffer* ctx_buf = new AlignedBuffer( ae_ctx_sizeof() );
fatal_assert( ctx_buf );
fatal_assert( AE_SUCCESS == ae_init( (ae_ctx *)ctx_buf->data(), key.data(), key.len(), NONCE_LEN, TAG_LEN ) );
fatal_assert( AE_SUCCESS == ae_init( (ae_ctx*)ctx_buf->data(), key.data(), key.len(), NONCE_LEN, TAG_LEN ) );
return ctx_buf;
}
static void scrap_ctx( AlignedBuffer &ctx_buf ) {
fatal_assert( AE_SUCCESS == ae_clear( (ae_ctx *)ctx_buf.data() ) );
static void scrap_ctx( AlignedBuffer& ctx_buf )
{
fatal_assert( AE_SUCCESS == ae_clear( (ae_ctx*)ctx_buf.data() ) );
}
static void test_encrypt( const AlignedBuffer &key, const AlignedBuffer &nonce,
const AlignedBuffer &plaintext, const AlignedBuffer &assoc,
const AlignedBuffer &expected_ciphertext ) {
static void test_encrypt( const AlignedBuffer& key,
const AlignedBuffer& nonce,
const AlignedBuffer& plaintext,
const AlignedBuffer& assoc,
const AlignedBuffer& expected_ciphertext )
{
AlignedPointer ctx_buf( get_ctx( key ) );
ae_ctx *ctx = (ae_ctx *)ctx_buf->data();
ae_ctx* ctx = (ae_ctx*)ctx_buf->data();
AlignedBuffer observed_ciphertext( plaintext.len() + TAG_LEN );
const int ret = ae_encrypt( ctx, nonce.data(),
plaintext.data(), plaintext.len(),
assoc.data(), assoc.len(),
observed_ciphertext.data(), NULL,
const int ret = ae_encrypt( ctx,
nonce.data(),
plaintext.data(),
plaintext.len(),
assoc.data(),
assoc.len(),
observed_ciphertext.data(),
NULL,
AE_FINALIZE );
if ( verbose ) {
printf( "ret %d\n", ret );
hexdump(observed_ciphertext, "obs ct" );
hexdump( observed_ciphertext, "obs ct" );
}
fatal_assert( ret == int( expected_ciphertext.len() ) );
@@ -99,19 +108,26 @@ static void test_encrypt( const AlignedBuffer &key, const AlignedBuffer &nonce,
scrap_ctx( *ctx_buf );
}
static void test_decrypt( const AlignedBuffer &key, const AlignedBuffer &nonce,
const AlignedBuffer &ciphertext, const AlignedBuffer &assoc,
const AlignedBuffer &expected_plaintext,
bool valid ) {
static void test_decrypt( const AlignedBuffer& key,
const AlignedBuffer& nonce,
const AlignedBuffer& ciphertext,
const AlignedBuffer& assoc,
const AlignedBuffer& expected_plaintext,
bool valid )
{
AlignedPointer ctx_buf( get_ctx( key ) );
ae_ctx *ctx = (ae_ctx *)ctx_buf->data();
ae_ctx* ctx = (ae_ctx*)ctx_buf->data();
AlignedBuffer observed_plaintext( ciphertext.len() - TAG_LEN );
const int ret = ae_decrypt( ctx, nonce.data(),
ciphertext.data(), ciphertext.len(),
assoc.data(), assoc.len(),
observed_plaintext.data(), NULL,
const int ret = ae_decrypt( ctx,
nonce.data(),
ciphertext.data(),
ciphertext.len(),
assoc.data(),
assoc.len(),
observed_plaintext.data(),
NULL,
AE_FINALIZE );
if ( verbose ) {
@@ -131,15 +147,20 @@ static void test_decrypt( const AlignedBuffer &key, const AlignedBuffer &nonce,
scrap_ctx( *ctx_buf );
}
static void test_vector( const char *key_p, const char *nonce_p,
size_t assoc_len, const char *assoc_p,
size_t plaintext_len, const char *plaintext_p,
size_t ciphertext_len, const char *ciphertext_p ) {
static void test_vector( const char* key_p,
const char* nonce_p,
size_t assoc_len,
const char* assoc_p,
size_t plaintext_len,
const char* plaintext_p,
size_t ciphertext_len,
const char* ciphertext_p )
{
AlignedBuffer key ( KEY_LEN, key_p );
AlignedBuffer nonce ( NONCE_LEN, nonce_p );
AlignedBuffer plaintext ( plaintext_len, plaintext_p );
AlignedBuffer assoc ( assoc_len, assoc_p );
AlignedBuffer key( KEY_LEN, key_p );
AlignedBuffer nonce( NONCE_LEN, nonce_p );
AlignedBuffer plaintext( plaintext_len, plaintext_p );
AlignedBuffer assoc( assoc_len, assoc_p );
AlignedBuffer ciphertext( ciphertext_len, ciphertext_p );
if ( verbose ) {
@@ -150,182 +171,198 @@ static void test_vector( const char *key_p, const char *nonce_p,
hexdump( ciphertext, "exp ct" );
}
test_encrypt( key, nonce, plaintext, assoc,
ciphertext );
test_encrypt( key, nonce, plaintext, assoc, ciphertext );
test_decrypt( key, nonce, ciphertext, assoc,
plaintext, true );
test_decrypt( key, nonce, ciphertext, assoc, plaintext, true );
/* Try some bad ciphertexts and make sure they don't validate. */
PRNG prng;
for ( size_t i=0; i<64; i++ ) {
for ( size_t i = 0; i < 64; i++ ) {
AlignedBuffer bad_ct( ciphertext.len(), ciphertext.data() );
( (uint8_t *) bad_ct.data() )[ prng.uint32() % bad_ct.len() ]
^= ( 1 << ( prng.uint8() % 8 ) );
test_decrypt( key, nonce, bad_ct, assoc,
plaintext, false );
( (uint8_t*)bad_ct.data() )[prng.uint32() % bad_ct.len()] ^= ( 1 << ( prng.uint8() % 8 ) );
test_decrypt( key, nonce, bad_ct, assoc, plaintext, false );
}
if (verbose) {
if ( verbose ) {
printf( "PASSED\n\n" );
}
}
#define TEST_VECTOR( _key, _nonce, _assoc, _pt, _ct ) \
test_vector( _key, _nonce, sizeof(_assoc)-1, _assoc, sizeof(_pt)-1, _pt, sizeof(_ct)-1, _ct )
test_vector( _key, _nonce, sizeof( _assoc ) - 1, _assoc, sizeof( _pt ) - 1, _pt, sizeof( _ct ) - 1, _ct )
static void test_all_vectors( void ) {
static void test_all_vectors( void )
{
/* Test vectors from http://tools.ietf.org/html/draft-krovetz-ocb-03#appendix-A */
const char ietf_key[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F";
const char ietf_nonce[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B";
TEST_VECTOR( ietf_key, ietf_nonce
, "" /* associated data */
, "" /* plaintext */
TEST_VECTOR( ietf_key,
ietf_nonce,
"" /* associated data */
,
"" /* plaintext */
/* ciphertext including tag */
, "\x19\x7B\x9C\x3C\x44\x1D\x3C\x83\xEA\xFB\x2B\xEF\x63\x3B\x91\x82" );
,
"\x19\x7B\x9C\x3C\x44\x1D\x3C\x83\xEA\xFB\x2B\xEF\x63\x3B\x91\x82" );
TEST_VECTOR( ietf_key, ietf_nonce
, "\x00\x01\x02\x03\x04\x05\x06\x07"
, "\x00\x01\x02\x03\x04\x05\x06\x07"
, "\x92\xB6\x57\x13\x0A\x74\xB8\x5A\x16\xDC\x76\xA4\x6D\x47\xE1\xEA"
TEST_VECTOR( ietf_key,
ietf_nonce,
"\x00\x01\x02\x03\x04\x05\x06\x07",
"\x00\x01\x02\x03\x04\x05\x06\x07",
"\x92\xB6\x57\x13\x0A\x74\xB8\x5A\x16\xDC\x76\xA4\x6D\x47\xE1\xEA"
"\xD5\x37\x20\x9E\x8A\x96\xD1\x4E" );
TEST_VECTOR( ietf_key, ietf_nonce
, "\x00\x01\x02\x03\x04\x05\x06\x07"
, ""
, "\x98\xB9\x15\x52\xC8\xC0\x09\x18\x50\x44\xE3\x0A\x6E\xB2\xFE\x21" );
TEST_VECTOR( ietf_key,
ietf_nonce,
"\x00\x01\x02\x03\x04\x05\x06\x07",
"",
"\x98\xB9\x15\x52\xC8\xC0\x09\x18\x50\x44\xE3\x0A\x6E\xB2\xFE\x21" );
TEST_VECTOR( ietf_key, ietf_nonce
, ""
, "\x00\x01\x02\x03\x04\x05\x06\x07"
, "\x92\xB6\x57\x13\x0A\x74\xB8\x5A\x97\x1E\xFF\xCA\xE1\x9A\xD4\x71"
TEST_VECTOR( ietf_key,
ietf_nonce,
"",
"\x00\x01\x02\x03\x04\x05\x06\x07",
"\x92\xB6\x57\x13\x0A\x74\xB8\x5A\x97\x1E\xFF\xCA\xE1\x9A\xD4\x71"
"\x6F\x88\xE8\x7B\x87\x1F\xBE\xED" );
TEST_VECTOR( ietf_key, ietf_nonce
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
TEST_VECTOR( ietf_key,
ietf_nonce,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
"\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
"\x77\x6C\x99\x24\xD6\x72\x3A\x1F\xC4\x52\x45\x32\xAC\x3E\x5B\xEB" );
TEST_VECTOR( ietf_key, ietf_nonce
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
, ""
, "\x7D\xDB\x8E\x6C\xEA\x68\x14\x86\x62\x12\x50\x96\x19\xB1\x9C\xC6" );
TEST_VECTOR( ietf_key,
ietf_nonce,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
"",
"\x7D\xDB\x8E\x6C\xEA\x68\x14\x86\x62\x12\x50\x96\x19\xB1\x9C\xC6" );
TEST_VECTOR( ietf_key, ietf_nonce
, ""
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
"\x13\xCC\x8B\x74\x78\x07\x12\x1A\x4C\xBB\x3E\x4B\xD6\xB4\x56\xAF");
TEST_VECTOR( ietf_key,
ietf_nonce,
"",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
"\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
"\x13\xCC\x8B\x74\x78\x07\x12\x1A\x4C\xBB\x3E\x4B\xD6\xB4\x56\xAF" );
TEST_VECTOR( ietf_key, ietf_nonce
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17"
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17"
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
TEST_VECTOR( ietf_key,
ietf_nonce,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17",
"\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
"\xFC\xFC\xEE\x7A\x2A\x8D\x4D\x48\x5F\xA9\x4F\xC3\xF3\x88\x20\xF1"
"\xDC\x3F\x3D\x1F\xD4\xE5\x5E\x1C" );
TEST_VECTOR( ietf_key, ietf_nonce
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17"
, ""
, "\x28\x20\x26\xDA\x30\x68\xBC\x9F\xA1\x18\x68\x1D\x55\x9F\x10\xF6" );
TEST_VECTOR( ietf_key,
ietf_nonce,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17",
"",
"\x28\x20\x26\xDA\x30\x68\xBC\x9F\xA1\x18\x68\x1D\x55\x9F\x10\xF6" );
TEST_VECTOR( ietf_key, ietf_nonce
, ""
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17"
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
TEST_VECTOR( ietf_key,
ietf_nonce,
"",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17",
"\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
"\xFC\xFC\xEE\x7A\x2A\x8D\x4D\x48\x6E\xF2\xF5\x25\x87\xFD\xA0\xED"
"\x97\xDC\x7E\xED\xE2\x41\xDF\x68" );
TEST_VECTOR( ietf_key, ietf_nonce
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17"
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17"
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
TEST_VECTOR( ietf_key,
ietf_nonce,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17",
"\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
"\xFC\xFC\xEE\x7A\x2A\x8D\x4D\x48\x5F\xA9\x4F\xC3\xF3\x88\x20\xF1"
"\xDC\x3F\x3D\x1F\xD4\xE5\x5E\x1C" );
TEST_VECTOR( ietf_key, ietf_nonce
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17"
, ""
, "\x28\x20\x26\xDA\x30\x68\xBC\x9F\xA1\x18\x68\x1D\x55\x9F\x10\xF6");
TEST_VECTOR( ietf_key,
ietf_nonce,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17",
"",
"\x28\x20\x26\xDA\x30\x68\xBC\x9F\xA1\x18\x68\x1D\x55\x9F\x10\xF6" );
TEST_VECTOR( ietf_key, ietf_nonce
, ""
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17"
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
TEST_VECTOR( ietf_key,
ietf_nonce,
"",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17",
"\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
"\xFC\xFC\xEE\x7A\x2A\x8D\x4D\x48\x6E\xF2\xF5\x25\x87\xFD\xA0\xED"
"\x97\xDC\x7E\xED\xE2\x41\xDF\x68" );
TEST_VECTOR( ietf_key, ietf_nonce
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
TEST_VECTOR( ietf_key,
ietf_nonce,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
"\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
"\xCE\xAA\xB9\xB0\x5D\xF7\x71\xA6\x57\x14\x9D\x53\x77\x34\x63\xCB"
"\xB2\xA0\x40\xDD\x3B\xD5\x16\x43\x72\xD7\x6D\x7B\xB6\x82\x42\x40" );
TEST_VECTOR( ietf_key, ietf_nonce
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
, ""
, "\xE1\xE0\x72\x63\x3B\xAD\xE5\x1A\x60\xE8\x59\x51\xD9\xC4\x2A\x1B" );
TEST_VECTOR( ietf_key,
ietf_nonce,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
"",
"\xE1\xE0\x72\x63\x3B\xAD\xE5\x1A\x60\xE8\x59\x51\xD9\xC4\x2A\x1B" );
TEST_VECTOR( ietf_key, ietf_nonce
, ""
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
TEST_VECTOR( ietf_key,
ietf_nonce,
"",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
"\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
"\xCE\xAA\xB9\xB0\x5D\xF7\x71\xA6\x57\x14\x9D\x53\x77\x34\x63\xCB"
"\x4A\x3B\xAE\x82\x44\x65\xCF\xDA\xF8\xC4\x1F\xC5\x0C\x7D\xF9\xD9" );
TEST_VECTOR( ietf_key, ietf_nonce
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
TEST_VECTOR( ietf_key,
ietf_nonce,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
"\x20\x21\x22\x23\x24\x25\x26\x27"
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x20\x21\x22\x23\x24\x25\x26\x27",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
"\x20\x21\x22\x23\x24\x25\x26\x27"
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
"\x20\x21\x22\x23\x24\x25\x26\x27",
"\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
"\xCE\xAA\xB9\xB0\x5D\xF7\x71\xA6\x57\x14\x9D\x53\x77\x34\x63\xCB"
"\x68\xC6\x57\x78\xB0\x58\xA6\x35\x65\x9C\x62\x32\x11\xDE\xEA\x0D"
"\xE3\x0D\x2C\x38\x18\x79\xF4\xC8" );
TEST_VECTOR( ietf_key, ietf_nonce
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
TEST_VECTOR( ietf_key,
ietf_nonce,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
"\x20\x21\x22\x23\x24\x25\x26\x27"
, ""
, "\x7A\xEB\x7A\x69\xA1\x68\x7D\xD0\x82\xCA\x27\xB0\xD9\xA3\x70\x96" );
"\x20\x21\x22\x23\x24\x25\x26\x27",
"",
"\x7A\xEB\x7A\x69\xA1\x68\x7D\xD0\x82\xCA\x27\xB0\xD9\xA3\x70\x96" );
TEST_VECTOR( ietf_key, ietf_nonce
, ""
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
TEST_VECTOR( ietf_key,
ietf_nonce,
"",
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
"\x20\x21\x22\x23\x24\x25\x26\x27"
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
"\x20\x21\x22\x23\x24\x25\x26\x27",
"\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22"
"\xCE\xAA\xB9\xB0\x5D\xF7\x71\xA6\x57\x14\x9D\x53\x77\x34\x63\xCB"
"\x68\xC6\x57\x78\xB0\x58\xA6\x35\x06\x0C\x84\x67\xF4\xAB\xAB\x5E"
"\x8B\x3C\x20\x67\xA2\xE1\x15\xDC" );
/* Some big texts. These were originally encrypted using this program;
they are regression tests. */
TEST_VECTOR(
"\x06\xF8\x9F\x69\xDA\x49\xDA\xD7\x68\x48\xFF\xB3\x60\xB6\x8F\x00"
, "\xDC\xBF\x85\x18\x23\xD9\x67\x85\x45\x59\x6F\xAD"
, ""
, "\xC4\x8E\x1F\x04\x10\x2F\xA5\x58\x68\x42\x62\xF3\x1B\xE7\x63\xA7"
TEST_VECTOR( "\x06\xF8\x9F\x69\xDA\x49\xDA\xD7\x68\x48\xFF\xB3\x60\xB6\x8F\x00",
"\xDC\xBF\x85\x18\x23\xD9\x67\x85\x45\x59\x6F\xAD",
"",
"\xC4\x8E\x1F\x04\x10\x2F\xA5\x58\x68\x42\x62\xF3\x1B\xE7\x63\xA7"
"\x77\x89\x64\x16\xE6\xB0\xF7\xFA\xFE\xF0\xB9\x50\x22\xDC\xCE\x78"
"\xA5\x01\xA4\x2D\xA2\x0F\x50\xEA\x9A\xAE\x23\x60\x1C\xC9\x11\x84"
"\x5F\xD0\x0A\x88\x99\xCD\xF1\x1B\x7C\xF9\x71\xC2\xD8\xE3\x7B\xB1"
@@ -356,8 +393,8 @@ static void test_all_vectors( void ) {
"\x2C\x2A\x86\x25\x77\x85\x14\x76\xD4\x51\xAB\xC7\x3A\xA7\xE1\xF7"
"\x23\xF7\x2B\xA3\xBA\xE4\x0B\xA4\x81\x9A\x83\x98\x69\xC3\x1C\x8A"
"\xBD\x26\x12\x36\x22\x9D\xCE\x85\x5D\xA3\xA0\xDF\x66\xD0\x59\xF6"
"\x47\xF2\xC5\x37\xF1\x62\x0D\x0C\x45\x5B\xE5\xFE\x3C\x8D\x28\x75"
, "\xa1\xd8\xa0\xe0\x75\x5c\xb4\xf4\xab\x59\x6d\x14\xfc\x2e\x75\x54"
"\x47\xF2\xC5\x37\xF1\x62\x0D\x0C\x45\x5B\xE5\xFE\x3C\x8D\x28\x75",
"\xa1\xd8\xa0\xe0\x75\x5c\xb4\xf4\xab\x59\x6d\x14\xfc\x2e\x75\x54"
"\xa3\x35\x4f\x57\x69\x48\x7a\x46\x17\x5f\xd9\x34\x50\xf9\x35\xe5"
"\x6f\xee\x27\xdb\x28\x0f\x06\x0b\xaf\xd5\x50\x4e\x20\x78\x35\xd6"
"\x4d\xa0\x18\xe8\x6c\x5b\x07\xbb\xb6\xd0\x3f\x4a\x0e\x14\x32\xaf"
@@ -391,11 +428,10 @@ static void test_all_vectors( void ) {
"\xa0\xb8\xe8\xcc\x8a\xe3\xcc\x0c\x92\xe6\xb1\xb0\xe2\xc1\x99\xca"
"\x1b\xa1\xac\x6e\x7a\x8a\xa0\x20\x3d\xeb\x29\x8b\xf4\x55\x41\x62" );
TEST_VECTOR(
"\x7A\x54\x0D\x3E\x56\x38\xF7\xC6\xCF\xAB\xF9\x56\xDC\xCA\x14\x23"
, "\x9B\x0E\xC1\x15\xD5\xE6\xC9\xAB\xE6\x88\x2A\x18"
, ""
, "\x52\xDB\xA7\x44\x2B\x1C\x9C\x24\x4D\xF3\xA1\xE4\x53\x7B\x9B\xB2"
TEST_VECTOR( "\x7A\x54\x0D\x3E\x56\x38\xF7\xC6\xCF\xAB\xF9\x56\xDC\xCA\x14\x23",
"\x9B\x0E\xC1\x15\xD5\xE6\xC9\xAB\xE6\x88\x2A\x18",
"",
"\x52\xDB\xA7\x44\x2B\x1C\x9C\x24\x4D\xF3\xA1\xE4\x53\x7B\x9B\xB2"
"\x25\xC5\xA3\x81\x42\x23\xA9\xB4\x12\xF8\xFC\xE4\xF6\x8E\x20\xD4"
"\x59\x7B\x39\x2D\x5D\x7C\x6E\xB7\x51\x02\x90\x7A\x8E\xAA\x30\xD0"
"\xEB\xDF\x70\x09\x5A\xEC\xFB\xD4\xDB\x0B\xE9\x1B\x79\xAF\x40\xA3"
@@ -426,8 +462,8 @@ static void test_all_vectors( void ) {
"\x9B\x3E\x3D\x6B\x56\x3B\x2B\xDC\x8A\x46\xF6\x7C\x36\xF9\x27\x29"
"\x37\x38\x7C\x9D\xA0\x6E\x5D\x4C\xE5\xB2\x6F\x0C\xDC\xEF\xFE\x35"
"\xFE\x3D\x56\x40\x7F\xBD\x4D\xDD\x40\x79\xDD\xA7\x0A\x7B\xA2\xCE"
"\x22\x38\x94\xEA\x90\xF5\x95\xB6\xE6\x6F\x14\xFB\xA2"
, "\xec\xa9\xcc\x30\x66\x6c\x04\x16\x21\x8d\xc8\x15\x47\xa2\x18\xcf"
"\x22\x38\x94\xEA\x90\xF5\x95\xB6\xE6\x6F\x14\xFB\xA2",
"\xec\xa9\xcc\x30\x66\x6c\x04\x16\x21\x8d\xc8\x15\x47\xa2\x18\xcf"
"\x19\x90\x4f\x82\x27\x25\xa2\x1e\xfa\x1c\xe4\x58\x78\x43\x52\x4c"
"\xac\x24\xde\xcb\xad\x80\x05\x7a\xeb\x2d\xc0\x33\x05\x31\x25\x44"
"\xd7\x11\xa1\xf2\xcb\x09\x6f\xf0\x14\x3c\x3f\xf2\xc7\x79\xfb\x3f"
@@ -465,13 +501,14 @@ static void test_all_vectors( void ) {
/* http://tools.ietf.org/html/draft-krovetz-ocb-03#appendix-A
also specifies an iterative test algorithm, which we implement here. */
static void test_iterative( void ) {
static void test_iterative( void )
{
/* Key is always all zeros */
AlignedBuffer key( KEY_LEN );
memset( key.data(), 0, KEY_LEN );
AlignedPointer ctx_buf( get_ctx( key ) );
ae_ctx *ctx = (ae_ctx *)ctx_buf->data();
ae_ctx* ctx = (ae_ctx*)ctx_buf->data();
AlignedBuffer nonce( NONCE_LEN );
memset( nonce.data(), 0, NONCE_LEN );
@@ -479,43 +516,32 @@ static void test_iterative( void ) {
/* The loop below fills this buffer in order.
Each iteration adds 2*i + 3*TAG_LEN bytes. */
AlignedBuffer accumulator( 22400 );
uint8_t *acc = (uint8_t *) accumulator.data();
uint8_t* acc = (uint8_t*)accumulator.data();
for ( size_t i=0; i<128; i++ ) {
for ( size_t i = 0; i < 128; i++ ) {
/* i bytes of zeros */
AlignedBuffer s( i );
memset( s.data(), 0, s.len() );
/* Nonce is 11 bytes of zeros followed by 1 byte i */
( (uint8_t *) nonce.data() )[ 11 ] = i;
( (uint8_t*)nonce.data() )[11] = i;
/* We can't write directly to acc because it might not be aligned. */
AlignedBuffer out( s.len() + TAG_LEN );
/* OCB-ENCRYPT(K,N,S,S) */
fatal_assert( 0 <= ae_encrypt( ctx, nonce.data(),
s.data(), s.len(),
s.data(), s.len(),
out.data(), NULL,
AE_FINALIZE ) );
fatal_assert(
0 <= ae_encrypt( ctx, nonce.data(), s.data(), s.len(), s.data(), s.len(), out.data(), NULL, AE_FINALIZE ) );
memcpy( acc, out.data(), s.len() + TAG_LEN );
acc += s.len() + TAG_LEN;
/* OCB-ENCRYPT(K,N,<empty string>,S) */
fatal_assert( 0 <= ae_encrypt( ctx, nonce.data(),
s.data(), s.len(),
NULL, 0,
out.data(), NULL,
AE_FINALIZE ) );
fatal_assert( 0 <= ae_encrypt( ctx, nonce.data(), s.data(), s.len(), NULL, 0, out.data(), NULL, AE_FINALIZE ) );
memcpy( acc, out.data(), s.len() + TAG_LEN );
acc += s.len() + TAG_LEN;
/* OCB-ENCRYPT(K,N,S,<empty string>) */
fatal_assert( 0 <= ae_encrypt( ctx, nonce.data(),
NULL, 0,
s.data(), s.len(),
out.data(), NULL,
AE_FINALIZE ) );
fatal_assert( 0 <= ae_encrypt( ctx, nonce.data(), NULL, 0, s.data(), s.len(), out.data(), NULL, AE_FINALIZE ) );
memcpy( acc, out.data(), TAG_LEN );
acc += TAG_LEN;
}
@@ -523,11 +549,9 @@ static void test_iterative( void ) {
/* OCB-ENCRYPT(K,N,C,<empty string>) */
AlignedBuffer out( TAG_LEN );
memset( nonce.data(), 0, NONCE_LEN );
fatal_assert( 0 <= ae_encrypt( ctx, nonce.data(),
NULL, 0,
accumulator.data(), accumulator.len(),
out.data(), NULL,
AE_FINALIZE ) );
fatal_assert(
0 <= ae_encrypt(
ctx, nonce.data(), NULL, 0, accumulator.data(), accumulator.len(), out.data(), NULL, AE_FINALIZE ) );
/* Check this final tag against the known value */
AlignedBuffer correct( TAG_LEN, "\xB2\xB4\x1C\xBF\x9B\x05\x03\x7D\xA7\xF1\x6C\x24\xA3\x5C\x1C\x94" );
@@ -539,16 +563,16 @@ static void test_iterative( void ) {
scrap_ctx( *ctx_buf );
}
int main( int argc, char *argv[] )
int main( int argc, char* argv[] )
{
if ( argc >= 2 && strcmp( argv[ 1 ], "-v" ) == 0 ) {
if ( argc >= 2 && strcmp( argv[1], "-v" ) == 0 ) {
verbose = true;
}
try {
test_all_vectors();
test_iterative();
} catch ( const std::exception &e ) {
} catch ( const std::exception& e ) {
fprintf( stderr, "Error: %s\r\n", e.what() );
return 1;
}
+8 -5
View File
@@ -34,22 +34,25 @@
#include "test_utils.h"
void hexdump( const void *buf, size_t len, const char *name ) {
const unsigned char *data = (const unsigned char *) buf;
void hexdump( const void* buf, size_t len, const char* name )
{
const unsigned char* data = (const unsigned char*)buf;
printf( DUMP_NAME_FMT, name );
for ( size_t i = 0; i < len; i++ ) {
// Although data[i] is an unsigned char, it will be promoted to a signed int
// when passed as an argument. Explicitly cast it back to an unsigned type
// so it can be printed in hex.
printf( "%02x", static_cast<unsigned>( data[ i ] ) );
printf( "%02x", static_cast<unsigned>( data[i] ) );
}
printf( "\n" );
}
void hexdump( const Crypto::AlignedBuffer &buf, const char *name ) {
void hexdump( const Crypto::AlignedBuffer& buf, const char* name )
{
hexdump( buf.data(), buf.len(), name );
}
void hexdump( const std::string &buf, const char *name ) {
void hexdump( const std::string& buf, const char* name )
{
hexdump( buf.data(), buf.size(), name );
}
+3 -3
View File
@@ -39,8 +39,8 @@
#define DUMP_NAME_FMT "%-10s "
void hexdump( const void *buf, size_t len, const char *name );
void hexdump( const Crypto::AlignedBuffer &buf, const char *name );
void hexdump( const std::string &buf, const char *name );
void hexdump( const void* buf, size_t len, const char* name );
void hexdump( const Crypto::AlignedBuffer& buf, const char* name );
void hexdump( const std::string& buf, const char* name );
#endif
+10 -8
View File
@@ -38,17 +38,19 @@
#include "src/crypto/crypto.h"
static void dos_detected( const char *expression, const char *file, int line, const char *function )
static void dos_detected( const char* expression, const char* file, int line, const char* function )
{
char buffer[ 2048 ];
snprintf( buffer, 2048, "Illegal counterparty input (possible denial of service) in function %s at %s:%d, failed test: %s\n",
function, file, line, expression );
char buffer[2048];
snprintf( buffer,
2048,
"Illegal counterparty input (possible denial of service) in function %s at %s:%d, failed test: %s\n",
function,
file,
line,
expression );
throw Crypto::CryptoException( buffer );
}
#define dos_assert(expr) \
((expr) \
? (void)0 \
: dos_detected (#expr, __FILE__, __LINE__, __func__ ))
#define dos_assert( expr ) ( ( expr ) ? (void)0 : dos_detected( #expr, __FILE__, __LINE__, __func__ ) )
#endif
+8 -7
View File
@@ -36,16 +36,17 @@
#include <cstdio>
#include <cstdlib>
static void fatal_error( const char *expression, const char *file, int line, const char *function )
static void fatal_error( const char* expression, const char* file, int line, const char* function )
{
fprintf( stderr, "Fatal assertion failure in function %s at %s:%d\nFailed test: %s\n",
function, file, line, expression );
fprintf( stderr,
"Fatal assertion failure in function %s at %s:%d\nFailed test: %s\n",
function,
file,
line,
expression );
abort();
}
#define fatal_assert(expr) \
((expr) \
? (void)0 \
: fatal_error (#expr, __FILE__, __LINE__, __func__ ))
#define fatal_assert( expr ) ( ( expr ) ? (void)0 : fatal_error( #expr, __FILE__, __LINE__, __func__ ) )
#endif
+13 -13
View File
@@ -45,7 +45,6 @@
#include "src/util/locale_utils.h"
const std::string LocaleVar::str( void ) const
{
if ( name.empty() ) {
@@ -57,22 +56,22 @@ const std::string LocaleVar::str( void ) const
const LocaleVar get_ctype( void )
{
/* Reimplement the search logic, just for diagnostics */
if ( const char *all = getenv( "LC_ALL" ) ) {
if ( const char* all = getenv( "LC_ALL" ) ) {
return LocaleVar( "LC_ALL", all );
} else if ( const char *ctype = getenv( "LC_CTYPE" ) ) {
} else if ( const char* ctype = getenv( "LC_CTYPE" ) ) {
return LocaleVar( "LC_CTYPE", ctype );
} else if ( const char *lang = getenv( "LANG" ) ) {
} else if ( const char* lang = getenv( "LANG" ) ) {
return LocaleVar( "LANG", lang );
}
return LocaleVar( "", "" );
}
const char *locale_charset( void )
const char* locale_charset( void )
{
static const char ASCII_name[] = "US-ASCII";
/* Produce more pleasant name of US-ASCII */
const char *ret = nl_langinfo( CODESET );
const char* ret = nl_langinfo( CODESET );
if ( strcmp( ret, "ANSI_X3.4-1968" ) == 0 ) {
ret = ASCII_name;
@@ -81,16 +80,17 @@ const char *locale_charset( void )
return ret;
}
bool is_utf8_locale( void ) {
bool is_utf8_locale( void )
{
/* Verify locale calls for UTF-8 */
if ( strcmp( locale_charset(), "UTF-8" ) != 0 &&
strcmp( locale_charset(), "utf-8" ) != 0 ) {
if ( strcmp( locale_charset(), "UTF-8" ) != 0 && strcmp( locale_charset(), "utf-8" ) != 0 ) {
return false;
}
return true;
}
void set_native_locale( void ) {
void set_native_locale( void )
{
/* Adopt native locale */
if ( NULL == setlocale( LC_ALL, "" ) ) {
int saved_errno = errno;
@@ -98,8 +98,7 @@ void set_native_locale( void ) {
LocaleVar ctype( get_ctype() );
fprintf( stderr, "The locale requested by %s isn't available here.\n", ctype.str().c_str() );
if ( !ctype.name.empty() ) {
fprintf( stderr, "Running `locale-gen %s' may be necessary.\n\n",
ctype.value.c_str() );
fprintf( stderr, "Running `locale-gen %s' may be necessary.\n\n", ctype.value.c_str() );
}
} else {
errno = saved_errno;
@@ -108,7 +107,8 @@ void set_native_locale( void ) {
}
}
void clear_locale_variables( void ) {
void clear_locale_variables( void )
{
unsetenv( "LANG" );
unsetenv( "LANGUAGE" );
unsetenv( "LC_CTYPE" );
+5 -6
View File
@@ -35,17 +35,16 @@
#include <string>
class LocaleVar {
public:
class LocaleVar
{
public:
const std::string name, value;
LocaleVar( const char *s_name, const char *s_value )
: name( s_name ), value( s_value )
{}
LocaleVar( const char* s_name, const char* s_value ) : name( s_name ), value( s_value ) {}
const std::string str( void ) const;
};
const LocaleVar get_ctype( void );
const char *locale_charset( void );
const char* locale_charset( void );
bool is_utf8_locale( void );
void set_native_locale( void );
void clear_locale_variables( void );
+14 -18
View File
@@ -32,7 +32,7 @@
#include "src/include/config.h"
#if !defined(HAVE_FORKPTY) || !defined(HAVE_CFMAKERAW)
#if !defined( HAVE_FORKPTY ) || !defined( HAVE_CFMAKERAW )
#include <cstdio>
#include <cstdlib>
#include <cstring>
@@ -46,13 +46,11 @@
#include "src/util/pty_compat.h"
#ifndef HAVE_FORKPTY
pid_t my_forkpty( int *amaster, char *name,
const struct termios *termp,
const struct winsize *winp )
pid_t my_forkpty( int* amaster, char* name, const struct termios* termp, const struct winsize* winp )
{
/* For Solaris and AIX */
int master, slave;
char *slave_name;
char* slave_name;
pid_t pid;
#ifdef _AIX
@@ -73,7 +71,7 @@ pid_t my_forkpty( int *amaster, char *name,
return -1;
}
if ( unlockpt(master) < 0 ) {
if ( unlockpt( master ) < 0 ) {
perror( "unlockpt" );
close( master );
return -1;
@@ -94,8 +92,7 @@ pid_t my_forkpty( int *amaster, char *name,
}
#ifndef _AIX
if ( ioctl(slave, I_PUSH, "ptem") < 0 ||
ioctl(slave, I_PUSH, "ldterm") < 0 ) {
if ( ioctl( slave, I_PUSH, "ptem" ) < 0 || ioctl( slave, I_PUSH, "ldterm" ) < 0 ) {
perror( "ioctl(I_PUSH)" );
close( slave );
close( master );
@@ -106,7 +103,7 @@ pid_t my_forkpty( int *amaster, char *name,
if ( amaster != NULL )
*amaster = master;
if ( name != NULL)
if ( name != NULL )
strcpy( name, slave_name );
if ( termp != NULL ) {
@@ -122,7 +119,7 @@ pid_t my_forkpty( int *amaster, char *name,
w.ws_col = 80;
w.ws_xpixel = 0;
w.ws_ypixel = 0;
if ( ioctl( slave, TIOCSWINSZ, &w) < 0 ) {
if ( ioctl( slave, TIOCSWINSZ, &w ) < 0 ) {
perror( "ioctl TIOCSWINSZ" );
exit( 1 );
}
@@ -149,12 +146,12 @@ pid_t my_forkpty( int *amaster, char *name,
#else
{
int dummy_fd;
dummy_fd = open (slave_name, O_RDWR);
if (dummy_fd < 0) {
dummy_fd = open( slave_name, O_RDWR );
if ( dummy_fd < 0 ) {
perror( "open(slave_name)" );
return -1;
}
close (dummy_fd);
close( dummy_fd );
}
#endif /* TIOCSCTTY */
close( master );
@@ -170,13 +167,12 @@ pid_t my_forkpty( int *amaster, char *name,
#endif
#ifndef HAVE_CFMAKERAW
void my_cfmakeraw( struct termios *termios_p )
void my_cfmakeraw( struct termios* termios_p )
{
termios_p->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
termios_p->c_iflag &= ~( IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON );
termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
termios_p->c_cflag &= ~(CSIZE | PARENB);
termios_p->c_lflag &= ~( ECHO | ECHONL | ICANON | ISIG | IEXTEN );
termios_p->c_cflag &= ~( CSIZE | PARENB );
termios_p->c_cflag |= CS8;
termios_p->c_cc[VMIN] = 1; // read() is satisfied after 1 char
+4 -6
View File
@@ -36,16 +36,14 @@
#include "src/include/config.h"
#ifndef HAVE_FORKPTY
# define forkpty my_forkpty
#define forkpty my_forkpty
#endif
#ifndef HAVE_CFMAKERAW
# define cfmakeraw my_cfmakeraw
#define cfmakeraw my_cfmakeraw
#endif
pid_t my_forkpty( int *amaster, char *name,
const struct termios *termp,
const struct winsize *winp );
pid_t my_forkpty( int* amaster, char* name, const struct termios* termp, const struct winsize* winp );
void my_cfmakeraw( struct termios *termios_p );
void my_cfmakeraw( struct termios* termios_p );
#endif
+2 -2
View File
@@ -43,6 +43,6 @@ void Select::handle_signal( int signum )
fatal_assert( signum >= 0 );
fatal_assert( signum <= MAX_SIGNAL_NUMBER );
Select &sel = get_instance();
sel.got_signal[ signum ] = 1;
Select& sel = get_instance();
sel.got_signal[signum] = 1;
}
+23 -24
View File
@@ -48,9 +48,11 @@
Any signals blocked by calling sigprocmask() outside this code will still be
received during Select::select(). So don't do that. */
class Select {
class Select
{
public:
static Select &get_instance( void ) {
static Select& get_instance( void )
{
/* COFU may or may not be thread-safe, depending on compiler */
static Select instance;
return instance;
@@ -61,10 +63,8 @@ private:
: max_fd( -1 )
/* These initializations are not used; they are just
here to appease -Weffc++. */
, all_fds( dummy_fd_set )
, read_fds( dummy_fd_set )
, empty_sigset( dummy_sigset )
, consecutive_polls( 0 )
,
all_fds( dummy_fd_set ), read_fds( dummy_fd_set ), empty_sigset( dummy_sigset ), consecutive_polls( 0 )
{
FD_ZERO( &all_fds );
FD_ZERO( &read_fds );
@@ -75,16 +75,15 @@ private:
void clear_got_signal( void )
{
for ( volatile sig_atomic_t *p = got_signal;
p < got_signal + sizeof( got_signal ) / sizeof( *got_signal );
for ( volatile sig_atomic_t* p = got_signal; p < got_signal + sizeof( got_signal ) / sizeof( *got_signal );
p++ ) {
*p = 0;
}
}
/* not implemented */
Select( const Select & );
Select &operator=( const Select & );
Select( const Select& );
Select& operator=( const Select& );
public:
void add_fd( int fd )
@@ -95,10 +94,7 @@ public:
FD_SET( fd, &all_fds );
}
void clear_fds( void )
{
FD_ZERO( &all_fds );
}
void clear_fds( void ) { FD_ZERO( &all_fds ); }
static void add_signal( int signum )
{
@@ -144,23 +140,23 @@ public:
#ifdef HAVE_PSELECT
struct timespec ts;
struct timespec *tsp = NULL;
struct timespec* tsp = NULL;
if ( timeout >= 0 ) {
ts.tv_sec = timeout / 1000;
ts.tv_nsec = 1000000 * (long( timeout ) % 1000);
ts.tv_nsec = 1000000 * ( long( timeout ) % 1000 );
tsp = &ts;
}
int ret = ::pselect( max_fd + 1, &read_fds, NULL, NULL, tsp, &empty_sigset );
#else
struct timeval tv;
struct timeval *tvp = NULL;
struct timeval* tvp = NULL;
sigset_t old_sigset;
if ( timeout >= 0 ) {
tv.tv_sec = timeout / 1000;
tv.tv_usec = 1000 * (long( timeout ) % 1000);
tv.tv_usec = 1000 * ( long( timeout ) % 1000 );
tvp = &tv;
}
@@ -205,8 +201,8 @@ public:
fatal_assert( signum >= 0 );
fatal_assert( signum <= MAX_SIGNAL_NUMBER );
/* XXX This requires a guard against concurrent signals. */
bool rv = got_signal[ signum ];
got_signal[ signum ] = 0;
bool rv = got_signal[signum];
got_signal[signum] = 0;
return rv;
}
@@ -214,13 +210,16 @@ public:
bool any_signal( void ) const
{
bool rv = false;
for (int i = 0; i < MAX_SIGNAL_NUMBER; i++) {
rv |= got_signal[ i ];
for ( int i = 0; i < MAX_SIGNAL_NUMBER; i++ ) {
rv |= got_signal[i];
}
return rv;
}
static void set_verbose( unsigned int s_verbose ) { verbose = s_verbose; }
static void set_verbose( unsigned int s_verbose )
{
verbose = s_verbose;
}
private:
static const int MAX_SIGNAL_NUMBER = 64;
@@ -234,7 +233,7 @@ private:
/* We assume writes to got_signal are atomic, though we also try to mask out
concurrent signal handlers. */
volatile sig_atomic_t got_signal[ MAX_SIGNAL_NUMBER + 1 ];
volatile sig_atomic_t got_signal[MAX_SIGNAL_NUMBER + 1];
fd_set all_fds, read_fds;
+3 -4
View File
@@ -37,13 +37,12 @@
#include "src/util/swrite.h"
int swrite( int fd, const char *str, ssize_t len )
int swrite( int fd, const char* str, ssize_t len )
{
ssize_t total_bytes_written = 0;
ssize_t bytes_to_write = ( len >= 0 ) ? len : (ssize_t) strlen( str );
ssize_t bytes_to_write = ( len >= 0 ) ? len : (ssize_t)strlen( str );
while ( total_bytes_written < bytes_to_write ) {
ssize_t bytes_written = write( fd, str + total_bytes_written,
bytes_to_write - total_bytes_written );
ssize_t bytes_written = write( fd, str + total_bytes_written, bytes_to_write - total_bytes_written );
if ( bytes_written <= 0 ) {
perror( "write" );
return -1;
+1 -1
View File
@@ -33,6 +33,6 @@
#ifndef SWRITE_HPP
#define SWRITE_HPP
int swrite( int fd, const char *str, ssize_t len = -1 );
int swrite( int fd, const char* str, ssize_t len = -1 );
#endif
+8 -8
View File
@@ -44,15 +44,15 @@
#include <mach/mach_time.h>
#endif
#if HAVE_GETTIMEOFDAY
#include <sys/time.h>
#include <cstdio>
#include <sys/time.h>
#endif
// On Apple systems CLOCK_MONOTONIC is unfortunately able to go
// backwards in time. This breaks mosh when system is returning from
// suspend as described in ticket #1014. To avoid this issue prefer
// CLOCK_MONOTONIC_RAW on Apple systems when available.
#if defined(__APPLE__) && defined(CLOCK_MONOTONIC_RAW)
#if defined( __APPLE__ ) && defined( CLOCK_MONOTONIC_RAW )
#define CLOCKTYPE CLOCK_MONOTONIC_RAW
#else
#define CLOCKTYPE CLOCK_MONOTONIC
@@ -79,7 +79,7 @@ void freeze_timestamp( void )
struct timespec tp;
if (
#if defined(__APPLE__) && defined(__MACH__)
#if defined( __APPLE__ ) && defined( __MACH__ )
// Check for presence, for OS X SDK >= 10.12 and runtime < 10.12
&clock_gettime != NULL &&
#endif
@@ -97,8 +97,8 @@ void freeze_timestamp( void )
static mach_timebase_info_data_t s_timebase_info;
static double absolute_to_millis = 0.0;
if (absolute_to_millis == 0.0) {
if (ERR_SUCCESS == mach_timebase_info(&s_timebase_info)) {
if ( absolute_to_millis == 0.0 ) {
if ( ERR_SUCCESS == mach_timebase_info( &s_timebase_info ) ) {
absolute_to_millis = 1e-6 * s_timebase_info.numer / s_timebase_info.denom;
} else
absolute_to_millis = -1.0;
@@ -106,7 +106,7 @@ void freeze_timestamp( void )
// NB: mach_absolute_time() returns "absolute time units"
// We need to apply a conversion to get milliseconds.
if (absolute_to_millis > 0.0) {
if ( absolute_to_millis > 0.0 ) {
millis_cache = mach_absolute_time() * absolute_to_millis;
return;
}
@@ -115,7 +115,7 @@ void freeze_timestamp( void )
// Not monotonic.
// NOTE: If time steps backwards, timeouts may be confused.
struct timeval tv;
if ( gettimeofday(&tv, NULL) ) {
if ( gettimeofday( &tv, NULL ) ) {
perror( "gettimeofday" );
} else {
uint64_t millis = tv.tv_usec / 1000;
@@ -125,6 +125,6 @@ void freeze_timestamp( void )
return;
}
#else
# error "gettimeofday() unavailable-- required as timer of last resort"
#error "gettimeofday() unavailable-- required as timer of last resort"
#endif
}