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
+1 -5
View File
@@ -72,11 +72,7 @@ int ae_ctx_sizeof(void); /* Return sizeof(ae_ctx) */
* *
* ----------------------------------------------------------------------- */ * ----------------------------------------------------------------------- */
int ae_init(ae_ctx *ctx, int ae_init( ae_ctx* ctx, const void* key, int key_len, int nonce_len, int tag_len );
const void *key,
int key_len,
int nonce_len,
int tag_len);
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
* *
* Initialize an ae_ctx context structure. * Initialize an ae_ctx context structure.
+3 -5
View File
@@ -33,8 +33,8 @@
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include "src/util/fatal_assert.h"
#include "src/crypto/base64.h" #include "src/crypto/base64.h"
#include "src/util/fatal_assert.h"
static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -65,8 +65,7 @@ static unsigned char base64_char_to_sixbit(unsigned char c)
return reverse[c]; return reverse[c];
} }
bool base64_decode( const char *b64, const size_t b64_len, bool base64_decode( const char* b64, const size_t b64_len, uint8_t* raw, size_t* raw_len )
uint8_t *raw, size_t *raw_len )
{ {
fatal_assert( b64_len == 24 ); /* only useful for Mosh keys */ fatal_assert( b64_len == 24 ); /* only useful for Mosh keys */
fatal_assert( *raw_len == 16 ); fatal_assert( *raw_len == 16 );
@@ -96,8 +95,7 @@ bool base64_decode( const char *b64, const size_t b64_len,
return true; return true;
} }
void base64_encode( const uint8_t *raw, const size_t raw_len, void base64_encode( const uint8_t* raw, const size_t raw_len, char* b64, const size_t b64_len )
char *b64, const size_t b64_len )
{ {
fatal_assert( b64_len == 24 ); /* only useful for Mosh keys */ fatal_assert( b64_len == 24 ); /* only useful for Mosh keys */
fatal_assert( raw_len == 16 ); fatal_assert( raw_len == 16 );
+2 -4
View File
@@ -32,8 +32,6 @@
#include <cstdint> #include <cstdint>
bool base64_decode( const char *b64, const size_t b64_len, bool base64_decode( const char* b64, const size_t b64_len, uint8_t* raw, size_t* raw_len );
uint8_t *raw, size_t *raw_len );
void base64_encode( const uint8_t *raw, const size_t raw_len, void base64_encode( const uint8_t* raw, const size_t raw_len, char* b64, const size_t b64_len );
char *b64, const size_t b64_len );
+15 -20
View File
@@ -40,8 +40,8 @@
#if defined( HAVE_ENDIAN_H ) #if defined( HAVE_ENDIAN_H )
#include <endian.h> #include <endian.h>
#elif defined( HAVE_SYS_ENDIAN_H ) #elif defined( HAVE_SYS_ENDIAN_H )
# include <sys/types.h>
#include <sys/endian.h> #include <sys/endian.h>
#include <sys/types.h>
#endif #endif
#if !HAVE_DECL_BE64TOH && HAVE_DECL_BETOH64 #if !HAVE_DECL_BE64TOH && HAVE_DECL_BETOH64
@@ -70,9 +70,9 @@
/* Use unions rather than casts, to comply with strict aliasing rules. */ /* Use unions rather than casts, to comply with strict aliasing rules. */
inline uint64_t htobe64( uint64_t x ) { inline uint64_t htobe64( uint64_t x )
uint8_t xs[ 8 ] = { {
static_cast<uint8_t>( ( x >> 56 ) & 0xFF ), uint8_t xs[8] = { static_cast<uint8_t>( ( x >> 56 ) & 0xFF ),
static_cast<uint8_t>( ( x >> 48 ) & 0xFF ), static_cast<uint8_t>( ( x >> 48 ) & 0xFF ),
static_cast<uint8_t>( ( x >> 40 ) & 0xFF ), static_cast<uint8_t>( ( x >> 40 ) & 0xFF ),
static_cast<uint8_t>( ( x >> 32 ) & 0xFF ), static_cast<uint8_t>( ( x >> 32 ) & 0xFF ),
@@ -88,26 +88,21 @@ inline uint64_t htobe64( uint64_t x ) {
return *u.p64; return *u.p64;
} }
inline uint64_t be64toh( uint64_t x ) { inline uint64_t be64toh( uint64_t x )
{
union { union {
const uint8_t* p8; const uint8_t* p8;
const uint64_t* p64; const uint64_t* p64;
} u; } u;
u.p64 = &x; u.p64 = &x;
return ( uint64_t( u.p8[ 0 ] ) << 56 ) return ( uint64_t( u.p8[0] ) << 56 ) | ( uint64_t( u.p8[1] ) << 48 ) | ( uint64_t( u.p8[2] ) << 40 )
| ( uint64_t( u.p8[ 1 ] ) << 48 ) | ( uint64_t( u.p8[3] ) << 32 ) | ( uint64_t( u.p8[4] ) << 24 ) | ( uint64_t( u.p8[5] ) << 16 )
| ( uint64_t( u.p8[ 2 ] ) << 40 ) | ( uint64_t( u.p8[6] ) << 8 ) | ( uint64_t( u.p8[7] ) );
| ( 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 ) { inline uint16_t htobe16( uint16_t x )
uint8_t xs[ 2 ] = { {
static_cast<uint8_t>( ( x >> 8 ) & 0xFF ), uint8_t xs[2] = { static_cast<uint8_t>( ( x >> 8 ) & 0xFF ), static_cast<uint8_t>( (x)&0xFF ) };
static_cast<uint8_t>( ( x ) & 0xFF ) };
union { union {
const uint8_t* p8; const uint8_t* p8;
const uint16_t* p16; const uint16_t* p16;
@@ -116,14 +111,14 @@ inline uint16_t htobe16( uint16_t x ) {
return *u.p16; return *u.p16;
} }
inline uint16_t be16toh( uint16_t x ) { inline uint16_t be16toh( uint16_t x )
{
union { union {
const uint8_t* p8; const uint8_t* p8;
const uint16_t* p16; const uint16_t* p16;
} u; } u;
u.p16 = &x; u.p16 = &x;
return ( uint16_t( u.p8[ 0 ] ) << 8 ) return ( uint16_t( u.p8[0] ) << 8 ) | ( uint16_t( u.p8[1] ) );
| ( uint16_t( u.p8[ 1 ] ) );
} }
#endif #endif
+16 -19
View File
@@ -39,11 +39,11 @@
#include <sys/resource.h> #include <sys/resource.h>
#include "src/crypto/base64.h"
#include "src/crypto/byteorder.h" #include "src/crypto/byteorder.h"
#include "src/crypto/crypto.h" #include "src/crypto/crypto.h"
#include "src/crypto/base64.h"
#include "src/util/fatal_assert.h"
#include "src/crypto/prng.h" #include "src/crypto/prng.h"
#include "src/util/fatal_assert.h"
using namespace Crypto; using namespace Crypto;
@@ -54,8 +54,7 @@ long int myatoi( const char *str )
errno = 0; errno = 0;
long int ret = strtol( str, &end, 10 ); long int ret = strtol( str, &end, 10 );
if ( ( errno != 0 ) if ( ( errno != 0 ) || ( end != str + strlen( str ) ) ) {
|| ( end != str + strlen( str ) ) ) {
throw CryptoException( "Bad integer." ); throw CryptoException( "Bad integer." );
} }
@@ -72,13 +71,11 @@ uint64_t Crypto::unique( void )
return rv; return rv;
} }
AlignedBuffer::AlignedBuffer( size_t len, const char *data ) AlignedBuffer::AlignedBuffer( size_t len, const char* data ) : m_len( len ), m_allocated( NULL ), m_data( NULL )
: m_len( len ), m_allocated( NULL ), m_data( NULL )
{ {
size_t alloc_len = len ? len : 1; size_t alloc_len = len ? len : 1;
#if defined( HAVE_POSIX_MEMALIGN ) #if defined( HAVE_POSIX_MEMALIGN )
if ( ( 0 != posix_memalign( &m_allocated, 16, alloc_len ) ) if ( ( 0 != posix_memalign( &m_allocated, 16, alloc_len ) ) || ( m_allocated == NULL ) ) {
|| ( m_allocated == NULL ) ) {
throw std::bad_alloc(); throw std::bad_alloc();
} }
m_data = (char*)m_allocated; m_data = (char*)m_allocated;
@@ -147,8 +144,7 @@ std::string Base64Key::printable_key( void ) const
base64_encode( key, 16, base64, 24 ); base64_encode( key, 16, base64, 24 );
if ( (base64[ 23 ] != '=') if ( ( base64[23] != '=' ) || ( base64[22] != '=' ) ) {
|| (base64[ 22 ] != '=') ) {
throw CryptoException( std::string( "Unexpected output from base64_encode: " ) + std::string( base64, 24 ) ); throw CryptoException( std::string( "Unexpected output from base64_encode: " ) + std::string( base64, 24 ) );
} }
@@ -157,11 +153,8 @@ std::string Base64Key::printable_key( void ) const
} }
Session::Session( Base64Key s_key ) Session::Session( Base64Key s_key )
: key( s_key ), ctx_buf( ae_ctx_sizeof() ), : key( s_key ), ctx_buf( ae_ctx_sizeof() ), ctx( (ae_ctx*)ctx_buf.data() ), blocks_encrypted( 0 ),
ctx( (ae_ctx *)ctx_buf.data() ), blocks_encrypted( 0 ), plaintext_buffer( RECEIVE_MTU ), ciphertext_buffer( RECEIVE_MTU ), nonce_buffer( Nonce::NONCE_LEN )
plaintext_buffer( RECEIVE_MTU ),
ciphertext_buffer( RECEIVE_MTU ),
nonce_buffer( Nonce::NONCE_LEN )
{ {
if ( AE_SUCCESS != ae_init( ctx, key.data(), 16, 12, 16 ) ) { if ( AE_SUCCESS != ae_init( ctx, key.data(), 16, 12, 16 ) ) {
throw CryptoException( "Could not initialize AES-OCB context." ); throw CryptoException( "Could not initialize AES-OCB context." );
@@ -209,7 +202,8 @@ const std::string Session::encrypt( const Message & plaintext )
memcpy( plaintext_buffer.data(), plaintext.text.data(), pt_len ); memcpy( plaintext_buffer.data(), plaintext.text.data(), pt_len );
memcpy( nonce_buffer.data(), plaintext.nonce.data(), Nonce::NONCE_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 */ nonce_buffer.data(), /* nonce */
plaintext_buffer.data(), /* pt */ plaintext_buffer.data(), /* pt */
pt_len, /* pt_len */ pt_len, /* pt_len */
@@ -269,7 +263,8 @@ const Message Session::decrypt( const char *str, size_t len )
memcpy( ciphertext_buffer.data(), str + 8, body_len ); memcpy( ciphertext_buffer.data(), str + 8, body_len );
memcpy( nonce_buffer.data(), nonce.data(), Nonce::NONCE_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 */ nonce_buffer.data(), /* nonce */
ciphertext_buffer.data(), /* ct */ ciphertext_buffer.data(), /* ct */
body_len, /* ct_len */ 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 /* Disable dumping core, as a precaution to avoid saving sensitive data
to disk. */ to disk. */
void Crypto::disable_dumping_core( void ) { void Crypto::disable_dumping_core( void )
{
struct rlimit limit; struct rlimit limit;
if ( 0 != getrlimit( RLIMIT_CORE, &limit ) ) { if ( 0 != getrlimit( RLIMIT_CORE, &limit ) ) {
/* We don't throw CryptoException because this is called very early /* 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. */ /* Silent failure is safe. */
struct rlimit limit; struct rlimit limit;
if ( 0 == getrlimit( RLIMIT_CORE, &limit ) ) { if ( 0 == getrlimit( RLIMIT_CORE, &limit ) ) {
+19 -22
View File
@@ -41,18 +41,17 @@
#include <exception> #include <exception>
#include <string> #include <string>
long int myatoi( const char* str ); long int myatoi( const char* str );
class PRNG; class PRNG;
namespace Crypto { namespace Crypto {
class CryptoException : public std::exception { class CryptoException : public std::exception
{
public: public:
std::string text; std::string text;
bool fatal; bool fatal;
CryptoException( std::string s_text, bool s_fatal = false ) CryptoException( std::string s_text, bool s_fatal = false ) : text( s_text ), fatal( s_fatal ) {};
: text( s_text ), fatal( s_fatal ) {};
const char* what() const throw() { return text.c_str(); } const char* what() const throw() { return text.c_str(); }
~CryptoException() throw() {} ~CryptoException() throw() {}
}; };
@@ -65,7 +64,8 @@ namespace Crypto {
uint64_t unique( void ); uint64_t unique( void );
/* 16-byte-aligned buffer, with length. */ /* 16-byte-aligned buffer, with length. */
class AlignedBuffer { class AlignedBuffer
{
private: private:
size_t m_len; size_t m_len;
void* m_allocated; void* m_allocated;
@@ -74,9 +74,7 @@ namespace Crypto {
public: public:
AlignedBuffer( size_t len, const char* data = NULL ); AlignedBuffer( size_t len, const char* data = NULL );
~AlignedBuffer() { ~AlignedBuffer() { free( m_allocated ); }
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; } size_t len( void ) const { return m_len; }
@@ -87,7 +85,8 @@ namespace Crypto {
AlignedBuffer& operator=( const AlignedBuffer& ); AlignedBuffer& operator=( const AlignedBuffer& );
}; };
class Base64Key { class Base64Key
{
private: private:
unsigned char key[16]; unsigned char key[16];
@@ -99,7 +98,8 @@ namespace Crypto {
unsigned char* data( void ) { return key; } unsigned char* data( void ) { return key; }
}; };
class Nonce { class Nonce
{
public: public:
static const int NONCE_LEN = 12; static const int NONCE_LEN = 12;
@@ -115,22 +115,21 @@ namespace Crypto {
uint64_t val( void ) const; uint64_t val( void ) const;
}; };
class Message { class Message
{
public: public:
const Nonce nonce; const Nonce nonce;
const std::string text; const std::string text;
Message( const char *nonce_bytes, size_t nonce_len, Message( const char* nonce_bytes, size_t nonce_len, const char* text_bytes, size_t text_len )
const char *text_bytes, size_t text_len ) : nonce( nonce_bytes, nonce_len ), text( text_bytes, text_len )
: nonce( nonce_bytes, nonce_len ), {}
text( text_bytes, text_len ) {}
Message( const Nonce & s_nonce, const std::string & s_text ) Message( const Nonce& s_nonce, const std::string& s_text ) : nonce( s_nonce ), text( s_text ) {}
: nonce( s_nonce ),
text( s_text ) {}
}; };
class Session { class Session
{
private: private:
Base64Key key; Base64Key key;
AlignedBuffer ctx_buf; AlignedBuffer ctx_buf;
@@ -151,9 +150,7 @@ namespace Crypto {
const std::string encrypt( const Message& plaintext ); const std::string encrypt( const Message& plaintext );
const Message decrypt( const char* str, size_t len ); const Message decrypt( const char* str, size_t len );
const Message decrypt( const std::string & ciphertext ) { const Message decrypt( const std::string& ciphertext ) { return decrypt( ciphertext.data(), ciphertext.size() ); }
return decrypt( ciphertext.data(), ciphertext.size() );
}
Session( const Session& ); Session( const Session& );
Session& operator=( const Session& ); Session& operator=( const Session& );
+69 -48
View File
@@ -1,32 +1,38 @@
#include "src/include/config.h"
#include "src/crypto/ae.h" #include "src/crypto/ae.h"
#include "src/include/config.h"
#include <cstring> #include <cstring>
#include <openssl/crypto.h> #include <openssl/crypto.h>
#include <openssl/evp.h> #include <openssl/evp.h>
struct _ae_ctx { struct _ae_ctx
{
EVP_CIPHER_CTX* enc_ctx; EVP_CIPHER_CTX* enc_ctx;
EVP_CIPHER_CTX* dec_ctx; EVP_CIPHER_CTX* dec_ctx;
int tag_len; int tag_len;
}; };
int ae_clear(ae_ctx* ctx) { int ae_clear( ae_ctx* ctx )
{
EVP_CIPHER_CTX_free( ctx->enc_ctx ); EVP_CIPHER_CTX_free( ctx->enc_ctx );
EVP_CIPHER_CTX_free( ctx->dec_ctx ); EVP_CIPHER_CTX_free( ctx->dec_ctx );
OPENSSL_cleanse( ctx, sizeof( *ctx ) ); OPENSSL_cleanse( ctx, sizeof( *ctx ) );
return AE_SUCCESS; return AE_SUCCESS;
} }
int ae_ctx_sizeof() { int ae_ctx_sizeof()
{
return sizeof( _ae_ctx ); return sizeof( _ae_ctx );
} }
// If direction is 1, initializes encryption. If 0, initializes // If direction is 1, initializes encryption. If 0, initializes
// decryption. See the documentation of EVP_CipherInit_ex // decryption. See the documentation of EVP_CipherInit_ex
static int ae_evp_cipher_init(EVP_CIPHER_CTX **in_ctx, int direction, static int ae_evp_cipher_init( EVP_CIPHER_CTX** in_ctx,
int direction,
const unsigned char* key, const unsigned char* key,
int nonce_len, int tag_len) { int nonce_len,
int tag_len )
{
// Create an OpenSSL EVP context. It does not yet have any specific // Create an OpenSSL EVP context. It does not yet have any specific
// cipher associated with it. // cipher associated with it.
if ( !( *in_ctx = EVP_CIPHER_CTX_new() ) ) { if ( !( *in_ctx = EVP_CIPHER_CTX_new() ) ) {
@@ -36,29 +42,31 @@ static int ae_evp_cipher_init(EVP_CIPHER_CTX **in_ctx, int direction,
// Although OCB-AES has the same initialization process between // Although OCB-AES has the same initialization process between
// encryption and decryption, an EVP_CIPHER_CTX must be initialized // encryption and decryption, an EVP_CIPHER_CTX must be initialized
// for a specific direction. // for a specific direction.
if (EVP_CipherInit_ex(ctx, EVP_aes_128_ocb(), if ( EVP_CipherInit_ex( ctx,
/*impl=*/NULL, /*key=*/key, /*iv=*/NULL, EVP_aes_128_ocb(),
direction) != 1) { /*impl=*/NULL,
/*key=*/key,
/*iv=*/NULL,
direction )
!= 1 ) {
return -3; return -3;
} }
// Attempt to set the nonce length. If it fails, the length must not // Attempt to set the nonce length. If it fails, the length must not
// be supported. However, that should have been handled by the // be supported. However, that should have been handled by the
// pre-condition check above. // pre-condition check above.
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, if ( EVP_CIPHER_CTX_ctrl( ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce_len, NULL ) != 1 ) {
nonce_len, NULL) != 1) {
return -3; return -3;
} }
// A NULL tag length means that EVP_CTRL_AEAD_SET_TAG is only being // A NULL tag length means that EVP_CTRL_AEAD_SET_TAG is only being
// used to set the length // used to set the length
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, if ( EVP_CIPHER_CTX_ctrl( ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, NULL ) != 1 ) {
tag_len, NULL) != 1) {
return -3; return -3;
} }
return AE_SUCCESS; return AE_SUCCESS;
} }
int ae_init(ae_ctx *ctx, const void *key, int key_len, int nonce_len, int ae_init( ae_ctx* ctx, const void* key, int key_len, int nonce_len, int tag_len )
int tag_len) { {
// Pre-condition: Only nonces of length 12 are supported. The // Pre-condition: Only nonces of length 12 are supported. The
// documentation of `ae_init` in ae.h specifies that `ctx` is // documentation of `ae_init` in ae.h specifies that `ctx` is
// untouched if an invalid configuration is requested. Delegating // untouched if an invalid configuration is requested. Delegating
@@ -72,25 +80,31 @@ int ae_init(ae_ctx *ctx, const void *key, int key_len, int nonce_len,
return AE_NOT_SUPPORTED; return AE_NOT_SUPPORTED;
} }
int r = AE_SUCCESS; int r = AE_SUCCESS;
if ((r = ae_evp_cipher_init(&ctx->enc_ctx, 1, if ( ( r = ae_evp_cipher_init(
reinterpret_cast<const unsigned char *>(key), &ctx->enc_ctx, 1, reinterpret_cast<const unsigned char*>( key ), nonce_len, tag_len ) )
nonce_len, tag_len))!= AE_SUCCESS) { != AE_SUCCESS ) {
return r; return r;
} }
if ((r = ae_evp_cipher_init(&ctx->dec_ctx, 0, if ( ( r = ae_evp_cipher_init(
reinterpret_cast<const unsigned char *>(key), &ctx->dec_ctx, 0, reinterpret_cast<const unsigned char*>( key ), nonce_len, tag_len ) )
nonce_len, tag_len)) != AE_SUCCESS) { != AE_SUCCESS ) {
return r; return r;
} }
ctx->tag_len = tag_len; ctx->tag_len = tag_len;
return AE_SUCCESS; return AE_SUCCESS;
} }
int ae_encrypt(ae_ctx *ctx, const void *nonce_ptr, const void *pt_ptr, int ae_encrypt( ae_ctx* ctx,
int pt_len, const void *ad_ptr, int ad_len, void *ct_ptr, const void* nonce_ptr,
void *tag, int final) { const void* pt_ptr,
const unsigned char *nonce = int pt_len,
reinterpret_cast<const unsigned char *>(nonce_ptr); 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* pt = reinterpret_cast<const unsigned char*>( pt_ptr );
const unsigned char* ad = reinterpret_cast<const unsigned char*>( ad_ptr ); const unsigned char* ad = reinterpret_cast<const unsigned char*>( ad_ptr );
unsigned char* ct = reinterpret_cast<unsigned char*>( ct_ptr ); unsigned char* ct = reinterpret_cast<unsigned char*>( ct_ptr );
@@ -101,18 +115,20 @@ int ae_encrypt(ae_ctx *ctx, const void *nonce_ptr, const void *pt_ptr,
if ( nonce == NULL ) { if ( nonce == NULL ) {
return AE_NOT_SUPPORTED; return AE_NOT_SUPPORTED;
} }
if (EVP_EncryptInit_ex(ctx->enc_ctx, /*type=*/NULL, /*impl=*/NULL, if ( EVP_EncryptInit_ex( ctx->enc_ctx,
/*key=*/NULL, nonce) != 1) { /*type=*/NULL,
/*impl=*/NULL,
/*key=*/NULL,
nonce )
!= 1 ) {
return -3; return -3;
} }
int len = 0; int len = 0;
if (ad != NULL && ad_len > 0 && if ( ad != NULL && ad_len > 0 && EVP_EncryptUpdate( ctx->enc_ctx, /*out=*/NULL, &len, ad, ad_len ) != 1 ) {
EVP_EncryptUpdate(ctx->enc_ctx, /*out=*/NULL, &len, ad, ad_len) != 1) {
return -3; return -3;
} }
len = 0; len = 0;
if (pt != NULL && pt_len > 0 && if ( pt != NULL && pt_len > 0 && EVP_EncryptUpdate( ctx->enc_ctx, ct, &len, pt, pt_len ) != 1 ) {
EVP_EncryptUpdate(ctx->enc_ctx, ct, &len, pt, pt_len) != 1) {
return -3; return -3;
} }
int ciphertext_len = len; int ciphertext_len = len;
@@ -123,8 +139,7 @@ int ae_encrypt(ae_ctx *ctx, const void *nonce_ptr, const void *pt_ptr,
// If `tag` is provided, the authentication tag goes // If `tag` is provided, the authentication tag goes
// there. Otherwise, it is appended after the ciphertext. // there. Otherwise, it is appended after the ciphertext.
void* tag_location = tag != NULL ? tag : ct + ciphertext_len; void* tag_location = tag != NULL ? tag : ct + ciphertext_len;
if (EVP_CIPHER_CTX_ctrl(ctx->enc_ctx, EVP_CTRL_AEAD_GET_TAG, if ( EVP_CIPHER_CTX_ctrl( ctx->enc_ctx, EVP_CTRL_AEAD_GET_TAG, ctx->tag_len, tag_location ) != 1 ) {
ctx->tag_len, tag_location) != 1) {
return -3; return -3;
} }
if ( tag == NULL ) { if ( tag == NULL ) {
@@ -133,12 +148,17 @@ int ae_encrypt(ae_ctx *ctx, const void *nonce_ptr, const void *pt_ptr,
return ciphertext_len; return ciphertext_len;
} }
int ae_decrypt( ae_ctx* ctx,
int ae_decrypt(ae_ctx *ctx, const void *nonce_ptr, const void *ct_ptr, const void* nonce_ptr,
int ct_len, const void *ad_ptr, int ad_len, void *pt_ptr, const void* ct_ptr,
const void *tag, int final) { int ct_len,
const unsigned char *nonce = const void* ad_ptr,
reinterpret_cast<const unsigned char *>(nonce_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* ct = reinterpret_cast<const unsigned char*>( ct_ptr );
const unsigned char* ad = reinterpret_cast<const unsigned char*>( ad_ptr ); const unsigned char* ad = reinterpret_cast<const unsigned char*>( ad_ptr );
unsigned char* pt = reinterpret_cast<unsigned char*>( pt_ptr ); unsigned char* pt = reinterpret_cast<unsigned char*>( pt_ptr );
@@ -159,18 +179,20 @@ int ae_decrypt(ae_ctx *ctx, const void *nonce_ptr, const void *ct_ptr,
if ( nonce == NULL ) { if ( nonce == NULL ) {
return AE_NOT_SUPPORTED; return AE_NOT_SUPPORTED;
} }
if (EVP_DecryptInit_ex(ctx->dec_ctx, /*type=*/NULL, /*impl=*/NULL, if ( EVP_DecryptInit_ex( ctx->dec_ctx,
/*key=*/NULL, nonce) != 1) { /*type=*/NULL,
/*impl=*/NULL,
/*key=*/NULL,
nonce )
!= 1 ) {
return -3; return -3;
} }
int len = 0; int len = 0;
if (ad != NULL && ad_len > 0 && if ( ad != NULL && ad_len > 0 && EVP_DecryptUpdate( ctx->dec_ctx, /*out=*/NULL, &len, ad, ad_len ) != 1 ) {
EVP_DecryptUpdate(ctx->dec_ctx, /*out=*/NULL, &len, ad, ad_len) != 1) {
return -3; return -3;
} }
len = 0; len = 0;
if (ct != NULL && ct_len > 0 && if ( ct != NULL && ct_len > 0 && EVP_DecryptUpdate( ctx->dec_ctx, pt, &len, ct, ct_len ) != 1 ) {
EVP_DecryptUpdate(ctx->dec_ctx, pt, &len, ct, ct_len) != 1) {
return -3; return -3;
} }
int plaintext_len = len; int plaintext_len = len;
@@ -178,8 +200,7 @@ int ae_decrypt(ae_ctx *ctx, const void *nonce_ptr, const void *ct_ptr,
// there. Otherwise, it's the last bytes of the ciphertext. (This is // there. Otherwise, it's the last bytes of the ciphertext. (This is
// a convention, not a requirement of OCB mode). // a convention, not a requirement of OCB mode).
const void* tag_location = tag != NULL ? tag : ct + ct_len; const void* tag_location = tag != NULL ? tag : ct + ct_len;
if (EVP_CIPHER_CTX_ctrl(ctx->dec_ctx, EVP_CTRL_AEAD_SET_TAG, if ( EVP_CIPHER_CTX_ctrl( ctx->dec_ctx, EVP_CTRL_AEAD_SET_TAG, ctx->tag_len, (void*)tag_location ) != 1 ) {
ctx->tag_len, (void *)tag_location) != 1) {
return -3; 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 ) {
+10 -5
View File
@@ -47,7 +47,8 @@ static const char rdev[] = "/dev/urandom";
using namespace Crypto; using namespace Crypto;
class PRNG { class PRNG
{
private: private:
std::ifstream randfile; std::ifstream randfile;
@@ -58,7 +59,8 @@ class PRNG {
public: public:
PRNG() : randfile( rdev, std::ifstream::in | std::ifstream::binary ) {} 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 ) { if ( 0 == size ) {
return; return;
} }
@@ -69,19 +71,22 @@ class PRNG {
} }
} }
uint8_t uint8() { uint8_t uint8()
{
uint8_t x; uint8_t x;
fill( &x, 1 ); fill( &x, 1 );
return x; return x;
} }
uint32_t uint32() { uint32_t uint32()
{
uint32_t x; uint32_t x;
fill( &x, 4 ); fill( &x, 4 );
return x; return x;
} }
uint64_t uint64() { uint64_t uint64()
{
uint64_t x; uint64_t x;
fill( &x, 8 ); fill( &x, 8 );
return x; return x;
+4 -6
View File
@@ -53,12 +53,12 @@
#include <util.h> #include <util.h>
#endif #endif
#include "src/util/swrite.h" #include "src/frontend/terminaloverlay.h"
#include "src/statesync/completeterminal.h" #include "src/statesync/completeterminal.h"
#include "src/statesync/user.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/fatal_assert.h"
#include "src/util/locale_utils.h"
#include "src/util/swrite.h"
const int ITERATIONS = 100000; const int ITERATIONS = 100000;
@@ -107,9 +107,7 @@ int main( int argc, char **argv )
overlays.apply( *new_state ); overlays.apply( *new_state );
/* calculate minimal difference from where we are */ /* calculate minimal difference from where we are */
const std::string diff( display.new_frame( false, const std::string diff( display.new_frame( false, *local_framebuffer, *new_state ) );
*local_framebuffer,
*new_state ) );
/* make sure to use diff */ /* make sure to use diff */
if ( diff.size() > INT_MAX ) { if ( diff.size() > INT_MAX ) {
+1 -2
View File
@@ -57,8 +57,7 @@ int main( int argc, char *argv[] )
Message message = session.decrypt( input.str() ); Message message = session.decrypt( input.str() );
fprintf( stderr, "Nonce = %ld\n", fprintf( stderr, "Nonce = %ld\n", (long)message.nonce.val() );
(long)message.nonce.val() );
std::cout << message.text; std::cout << message.text;
} catch ( const CryptoException& e ) { } catch ( const CryptoException& e ) {
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
+5 -8
View File
@@ -35,10 +35,10 @@
#include <termios.h> #include <termios.h>
#include <unistd.h> #include <unistd.h>
#include "src/network/networktransport-impl.h"
#include "src/statesync/user.h" #include "src/statesync/user.h"
#include "src/util/fatal_assert.h" #include "src/util/fatal_assert.h"
#include "src/util/pty_compat.h" #include "src/util/pty_compat.h"
#include "src/network/networktransport-impl.h"
#include "src/util/select.h" #include "src/util/select.h"
using namespace Network; using namespace Network;
@@ -94,7 +94,8 @@ int main( int argc, char *argv[] )
n->recv(); n->recv();
if ( n->get_remote_state_num() != last_num ) { 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(); last_num = n->get_remote_state_num();
} }
} }
@@ -127,9 +128,7 @@ int main( int argc, char *argv[] )
sel.add_fd( STDIN_FILENO ); sel.add_fd( STDIN_FILENO );
std::vector<int> fd_list( n->fds() ); std::vector<int> fd_list( n->fds() );
for ( std::vector< int >::const_iterator it = fd_list.begin(); for ( std::vector<int>::const_iterator it = fd_list.begin(); it != fd_list.end(); it++ ) {
it != fd_list.end();
it++ ) {
sel.add_fd( *it ); sel.add_fd( *it );
} }
@@ -147,9 +146,7 @@ int main( int argc, char *argv[] )
} }
bool network_ready_to_read = false; bool network_ready_to_read = false;
for ( std::vector< int >::const_iterator it = fd_list.begin(); for ( std::vector<int>::const_iterator it = fd_list.begin(); it != fd_list.end(); it++ ) {
it != fd_list.end();
it++ ) {
if ( sel.read( *it ) ) { if ( sel.read( *it ) ) {
/* packet received from the network */ /* packet received from the network */
/* we only read one socket each run */ /* we only read one socket each run */
+7 -9
View File
@@ -55,11 +55,11 @@
#endif #endif
#include "src/terminal/parser.h" #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/fatal_assert.h"
#include "src/util/locale_utils.h"
#include "src/util/pty_compat.h" #include "src/util/pty_compat.h"
#include "src/util/select.h" #include "src/util/select.h"
#include "src/util/swrite.h"
const size_t buf_size = 1024; const size_t buf_size = 1024;
@@ -67,9 +67,7 @@ static void emulate_terminal( int fd );
static int copy( int src, int dest ); 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)), int main( int argc __attribute__( ( unused ) ), char* argv[] __attribute__( ( unused ) ), char* envp[] )
char *argv[] __attribute__((unused)),
char *envp[] )
{ {
int master; int master;
struct termios saved_termios, raw_termios, child_termios; struct termios saved_termios, raw_termios, child_termios;
@@ -90,7 +88,9 @@ int main( int argc __attribute__((unused)),
child_termios.c_iflag |= IUTF8; child_termios.c_iflag |= IUTF8;
} }
#else #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 */ #endif /* HAVE_IUTF8 */
pid_t child = forkpty( &master, NULL, &child_termios, NULL ); pid_t child = forkpty( &master, NULL, &child_termios, NULL );
@@ -196,9 +196,7 @@ static int vt_parser( int fd, Parser::UTF8Parser *parser )
Parser::Actions actions; Parser::Actions actions;
for ( int i = 0; i < bytes_read; i++ ) { for ( int i = 0; i < bytes_read; i++ ) {
parser->input( buf[i], actions ); parser->input( buf[i], actions );
for ( Parser::Actions::iterator j = actions.begin(); for ( Parser::Actions::iterator j = actions.begin(); j != actions.end(); j++ ) {
j != actions.end();
j++ ) {
assert( *j ); assert( *j );
Parser::Action& act = **j; Parser::Action& act = **j;
+9 -10
View File
@@ -61,13 +61,13 @@
#include <libutil.h> #include <libutil.h>
#endif #endif
#include "src/terminal/parser.h"
#include "src/statesync/completeterminal.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/fatal_assert.h"
#include "src/util/pty_compat.h"
#include "src/util/locale_utils.h" #include "src/util/locale_utils.h"
#include "src/util/pty_compat.h"
#include "src/util/select.h" #include "src/util/select.h"
#include "src/util/swrite.h"
const size_t buf_size = 16384; const size_t buf_size = 16384;
@@ -94,7 +94,9 @@ int main( int argc, char *argv[] )
child_termios.c_iflag |= IUTF8; child_termios.c_iflag |= IUTF8;
} }
#else #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 */ #endif /* HAVE_IUTF8 */
pid_t child = forkpty( &master, NULL, &child_termios, NULL ); pid_t child = forkpty( &master, NULL, &child_termios, NULL );
@@ -170,8 +172,7 @@ int main( int argc, char *argv[] )
} }
/* Print a frame if the last frame was more than 1/50 seconds ago */ /* Print a frame if the last frame was more than 1/50 seconds ago */
static bool tick( Terminal::Framebuffer &state, Terminal::Framebuffer &new_frame, static bool tick( Terminal::Framebuffer& state, Terminal::Framebuffer& new_frame, const Terminal::Display& display )
const Terminal::Display &display )
{ {
static bool initialized = false; static bool initialized = false;
static struct timeval last_time; static struct timeval last_time;
@@ -182,11 +183,9 @@ static bool tick( Terminal::Framebuffer &state, Terminal::Framebuffer &new_frame
perror( "gettimeofday" ); perror( "gettimeofday" );
} }
double diff = (this_time.tv_sec - last_time.tv_sec) double diff = ( this_time.tv_sec - last_time.tv_sec ) + .000001 * ( this_time.tv_usec - last_time.tv_usec );
+ .000001 * (this_time.tv_usec - last_time.tv_usec);
if ( (!initialized) if ( ( !initialized ) || ( diff >= 0.02 ) ) {
|| (diff >= 0.02) ) {
std::string update = display.new_frame( initialized, state, new_frame ); std::string update = display.new_frame( initialized, state, new_frame );
swrite( STDOUT_FILENO, update.c_str() ); swrite( STDOUT_FILENO, update.c_str() );
state = new_frame; state = new_frame;
+13 -13
View File
@@ -37,10 +37,10 @@
#include <unistd.h> #include <unistd.h>
#include "stmclient.h"
#include "src/crypto/crypto.h" #include "src/crypto/crypto.h"
#include "src/util/locale_utils.h"
#include "src/util/fatal_assert.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. */ /* These need to be included last because of conflicting defines. */
/* /*
@@ -77,14 +77,18 @@ static void print_version( FILE *file )
"Copyright 2012 Keith Winstein <mosh-devel@mit.edu>\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" "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" "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 ); print_version( file );
fprintf( file, "\nUsage: %s [-# 'ARGS'] IP PORT\n" fprintf( file,
" %s -c\n", argv0, argv0 ); "\nUsage: %s [-# 'ARGS'] IP PORT\n"
" %s -c\n",
argv0,
argv0 );
} }
static void print_colorcount( void ) static void print_colorcount( void )
@@ -95,8 +99,7 @@ static void print_colorcount( void )
char colors_name[] = "colors"; char colors_name[] = "colors";
int color_val = tigetnum( colors_name ); int color_val = tigetnum( colors_name );
if ( color_val == -2 ) { if ( color_val == -2 ) {
fprintf( stderr, "Invalid terminfo numeric capability: %s\n", fprintf( stderr, "Invalid terminfo numeric capability: %s\n", colors_name );
colors_name );
} }
printf( "%d\n", color_val ); printf( "%d\n", color_val );
@@ -158,8 +161,7 @@ int main( int argc, char *argv[] )
desired_port = argv[optind + 1]; desired_port = argv[optind + 1];
/* Sanity-check arguments */ /* Sanity-check arguments */
if ( desired_port if ( desired_port && ( strspn( desired_port, "0123456789" ) != strlen( desired_port ) ) ) {
&& ( strspn( desired_port, "0123456789" ) != strlen( desired_port ) ) ) {
fprintf( stderr, "%s: Bad UDP port (%s)\n\n", argv[0], desired_port ); fprintf( stderr, "%s: Bad UDP port (%s)\n\n", argv[0], desired_port );
print_usage( stderr, argv[0] ); print_usage( stderr, argv[0] );
exit( 1 ); exit( 1 );
@@ -204,12 +206,10 @@ int main( int argc, char *argv[] )
client.shutdown(); client.shutdown();
} catch ( const Network::NetworkException& e ) { } catch ( const Network::NetworkException& e ) {
fprintf( stderr, "Network exception: %s\r\n", fprintf( stderr, "Network exception: %s\r\n", e.what() );
e.what() );
success = false; success = false;
} catch ( const Crypto::CryptoException& e ) { } catch ( const Crypto::CryptoException& e ) {
fprintf( stderr, "Crypto exception: %s\r\n", fprintf( stderr, "Crypto exception: %s\r\n", e.what() );
e.what() );
success = false; success = false;
} catch ( const std::exception& e ) { } catch ( const std::exception& e ) {
fprintf( stderr, "Error: %s\r\n", e.what() ); fprintf( stderr, "Error: %s\r\n", e.what() );
+66 -65
View File
@@ -81,14 +81,13 @@
#endif #endif
#include "src/statesync/completeterminal.h" #include "src/statesync/completeterminal.h"
#include "src/util/swrite.h"
#include "src/statesync/user.h" #include "src/statesync/user.h"
#include "src/util/fatal_assert.h" #include "src/util/fatal_assert.h"
#include "src/util/locale_utils.h" #include "src/util/locale_utils.h"
#include "src/util/pty_compat.h" #include "src/util/pty_compat.h"
#include "src/util/select.h" #include "src/util/select.h"
#include "src/util/swrite.h"
#include "src/util/timestamp.h" #include "src/util/timestamp.h"
#include "src/util/fatal_assert.h"
#ifndef _PATH_BSHELL #ifndef _PATH_BSHELL
#define _PATH_BSHELL "/bin/sh" #define _PATH_BSHELL "/bin/sh"
@@ -105,10 +104,13 @@ static void serve( int host_fd,
long network_timeout, long network_timeout,
long network_signaled_timeout ); long network_signaled_timeout );
static int run_server( const char *desired_ip, const char *desired_port, static int run_server( const char* desired_ip,
const std::string &command_path, char *command_argv[], const char* desired_port,
const int colors, unsigned int verbose, bool with_motd ); 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 )
{ {
@@ -116,12 +118,15 @@ static void print_version( FILE *file )
"Copyright 2012 Keith Winstein <mosh-devel@mit.edu>\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" "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" "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 );
@@ -208,8 +213,7 @@ int main( int argc, char *argv[] )
} }
/* Parse new command-line syntax */ /* Parse new command-line syntax */
if ( (argc >= 2) if ( ( argc >= 2 ) && ( strcmp( argv[1], "new" ) == 0 ) ) {
&& (strcmp( argv[ 1 ], "new" ) == 0) ) {
/* new option syntax */ /* new option syntax */
int opt; 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 ) {
@@ -338,9 +342,7 @@ int main( int argc, char *argv[] )
/* apply locale-related environment variables from client */ /* apply locale-related environment variables from client */
clear_locale_variables(); clear_locale_variables();
for ( std::list<std::string>::const_iterator i = locale_vars.begin(); for ( std::list<std::string>::const_iterator i = locale_vars.begin(); i != locale_vars.end(); i++ ) {
i != locale_vars.end();
i++ ) {
char* env_string = strdup( i->c_str() ); char* env_string = strdup( i->c_str() );
fatal_assert( env_string ); fatal_assert( env_string );
if ( 0 != putenv( env_string ) ) { if ( 0 != putenv( env_string ) ) {
@@ -354,12 +356,16 @@ int main( int argc, char *argv[] )
LocaleVar client_ctype = get_ctype(); LocaleVar client_ctype = get_ctype();
std::string client_charset( locale_charset() ); 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" "Unfortunately, the local environment (%s) specifies\n"
"the character set \"%s\",\n\n" "the character set \"%s\",\n\n"
"The client-supplied environment (%s) specifies\n" "The client-supplied environment (%s) specifies\n"
"the character set \"%s\".\n\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() ); native_ctype.str().c_str(),
native_charset.c_str(),
client_ctype.str().c_str(),
client_charset.c_str() );
int unused __attribute( ( unused ) ) = system( "locale" ); int unused __attribute( ( unused ) ) = system( "locale" );
exit( 1 ); exit( 1 );
} }
@@ -368,19 +374,22 @@ int main( int argc, char *argv[] )
try { try {
return run_server( desired_ip, desired_port, command_path, command_argv, colors, verbose, with_motd ); return run_server( desired_ip, desired_port, command_path, command_argv, colors, verbose, with_motd );
} catch ( const Network::NetworkException& e ) { } catch ( const Network::NetworkException& e ) {
fprintf( stderr, "Network exception: %s\n", fprintf( stderr, "Network exception: %s\n", e.what() );
e.what() );
return 1; return 1;
} catch ( const Crypto::CryptoException& e ) { } catch ( const Crypto::CryptoException& e ) {
fprintf( stderr, "Crypto exception: %s\n", fprintf( stderr, "Crypto exception: %s\n", e.what() );
e.what() );
return 1; return 1;
} }
} }
static int run_server( const char *desired_ip, const char *desired_port, static int run_server( const char* desired_ip,
const std::string &command_path, char *command_argv[], const char* desired_port,
const int colors, unsigned int verbose, bool with_motd ) { const std::string& command_path,
char* command_argv[],
const int colors,
unsigned int verbose,
bool with_motd )
{
/* get network idle timeout */ /* get network idle timeout */
long network_timeout = 0; long network_timeout = 0;
char* timeout_envar = getenv( "MOSH_SERVER_NETWORK_TMOUT" ); char* timeout_envar = getenv( "MOSH_SERVER_NETWORK_TMOUT" );
@@ -411,9 +420,7 @@ static int run_server( const char *desired_ip, const char *desired_port,
} }
/* get initial window size */ /* get initial window size */
struct winsize window_size; struct winsize window_size;
if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 || if ( ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) < 0 || window_size.ws_col == 0 || window_size.ws_row == 0 ) {
window_size.ws_col == 0 ||
window_size.ws_row == 0 ) {
/* Fill in sensible defaults. */ /* Fill in sensible defaults. */
/* They will be overwritten by client on first connection. */ /* They will be overwritten by client on first connection. */
memset( &window_size, 0, sizeof( window_size ) ); 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( SIGHUP, &sa, NULL ) );
fatal_assert( 0 == sigaction( SIGPIPE, &sa, NULL ) ); fatal_assert( 0 == sigaction( SIGPIPE, &sa, NULL ) );
/* detach from terminal */ /* detach from terminal */
fflush( NULL ); fflush( NULL );
pid_t the_pid = fork(); 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" "Copyright 2012 Keith Winstein <mosh-devel@mit.edu>\n"
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\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" "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 #ifndef HAVE_IUTF8
fputs( "\nWarning: termios IUTF8 flag not defined.\n" fputs( "\nWarning: termios IUTF8 flag not defined.\n"
"Character-erase of multibyte character sequence\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 */ #endif /* HAVE_IUTF8 */
fflush( NULL ); fflush( NULL );
@@ -493,9 +501,8 @@ static int run_server( const char *desired_ip, const char *desired_port,
exit( 1 ); exit( 1 );
} }
if ( dup2 ( nullfd, STDIN_FILENO ) < 0 || if ( dup2( nullfd, STDIN_FILENO ) < 0 || dup2( nullfd, STDOUT_FILENO ) < 0
dup2 ( nullfd, STDOUT_FILENO ) < 0 || || dup2( nullfd, STDERR_FILENO ) < 0 ) {
dup2 ( nullfd, STDERR_FILENO ) < 0 ) {
perror( "dup2" ); perror( "dup2" );
exit( 1 ); exit( 1 );
} }
@@ -648,11 +655,9 @@ static int run_server( const char *desired_ip, const char *desired_port,
try { try {
serve( master, pipes[1], terminal, *network, network_timeout, network_signaled_timeout ); serve( master, pipes[1], terminal, *network, network_timeout, network_signaled_timeout );
} catch ( const Network::NetworkException& e ) { } catch ( const Network::NetworkException& e ) {
fprintf( stderr, "Network exception: %s\n", fprintf( stderr, "Network exception: %s\n", e.what() );
e.what() );
} catch ( const Crypto::CryptoException& e ) { } catch ( const Crypto::CryptoException& e ) {
fprintf( stderr, "Crypto exception: %s\n", fprintf( stderr, "Crypto exception: %s\n", e.what() );
e.what() );
} }
#ifdef HAVE_UTEMPTER #ifdef HAVE_UTEMPTER
@@ -670,7 +675,12 @@ static int run_server( const char *desired_ip, const char *desired_port,
return 0; 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 */ /* scale timeouts */
const uint64_t network_timeout_ms = static_cast<uint64_t>( network_timeout ) * 1000; const uint64_t network_timeout_ms = static_cast<uint64_t>( network_timeout ) * 1000;
@@ -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, network.wait_time() );
timeout = std::min( timeout, terminal.wait_time( now ) ); timeout = std::min( timeout, terminal.wait_time( now ) );
if ( (!network.get_remote_state_num()) if ( ( !network.get_remote_state_num() ) || network.shutdown_in_progress() ) {
|| network.shutdown_in_progress() ) {
timeout = std::min( timeout, 5000 ); timeout = std::min( timeout, 5000 );
} }
/* /*
@@ -719,8 +728,7 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve
* We may want to wake up sooner. * We may want to wake up sooner.
*/ */
if ( network_timeout_ms ) { if ( network_timeout_ms ) {
int64_t network_sleep = network_timeout_ms - int64_t network_sleep = network_timeout_ms - ( now - network.get_latest_remote_state().timestamp );
( now - network.get_latest_remote_state().timestamp );
if ( network_sleep < 0 ) { if ( network_sleep < 0 ) {
network_sleep = 0; network_sleep = 0;
} else if ( network_sleep > INT_MAX ) { } else if ( network_sleep > INT_MAX ) {
@@ -758,7 +766,6 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve
if ( network.get_remote_state_num() != last_remote_num ) { if ( network.get_remote_state_num() != last_remote_num ) {
last_remote_num = network.get_remote_state_num(); last_remote_num = network.get_remote_state_num();
Network::UserStream us; Network::UserStream us;
us.apply_string( network.get_remote_diff() ); us.apply_string( network.get_remote_diff() );
/* apply userstream to terminal */ /* apply userstream to terminal */
@@ -813,18 +820,15 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve
* - HAVE_UTEMPTER - update utmp entry if we have become "connected" * - HAVE_UTEMPTER - update utmp entry if we have become "connected"
* - HAVE_SYSLOG - log connection information to syslog * - HAVE_SYSLOG - log connection information to syslog
**/ **/
if ( (force_connection_change_evt) if ( ( force_connection_change_evt ) || saved_addr_len != network.get_remote_addr_len()
|| saved_addr_len != network.get_remote_addr_len() || memcmp( &saved_addr, &network.get_remote_addr(), saved_addr_len ) != 0 ) {
|| memcmp( &saved_addr, &network.get_remote_addr(),
saved_addr_len ) != 0 ) {
saved_addr = network.get_remote_addr(); saved_addr = network.get_remote_addr();
saved_addr_len = network.get_remote_addr_len(); saved_addr_len = network.get_remote_addr_len();
char host[NI_MAXHOST]; char host[NI_MAXHOST];
int errcode = getnameinfo( &saved_addr.sa, saved_addr_len, int errcode
host, sizeof( host ), NULL, 0, = getnameinfo( &saved_addr.sa, saved_addr_len, host, sizeof( host ), NULL, 0, NI_NUMERICHOST );
NI_NUMERICHOST );
if ( errcode != 0 ) { if ( errcode != 0 ) {
throw NetworkException( std::string( "serve: getnameinfo: " ) + gai_strerror( errcode ), 0 ); throw NetworkException( std::string( "serve: getnameinfo: " ) + gai_strerror( errcode ), 0 );
} }
@@ -880,16 +884,17 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve
} }
bool idle_shutdown = false; bool idle_shutdown = false;
if ( network_timeout_ms && if ( network_timeout_ms && network_timeout_ms <= time_since_remote_state ) {
network_timeout_ms <= time_since_remote_state ) {
idle_shutdown = true; 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 ) ); static_cast<unsigned long long>( time_since_remote_state / 1000 ) );
} }
if ( sel.signal( SIGUSR1 ) if ( sel.signal( SIGUSR1 )
&& ( !network_signaled_timeout_ms || network_signaled_timeout_ms <= time_since_remote_state ) ) { && ( !network_signaled_timeout_ms || network_signaled_timeout_ms <= time_since_remote_state ) ) {
idle_shutdown = true; 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 ) ); static_cast<unsigned long long>( time_since_remote_state / 1000 ) );
} }
@@ -919,8 +924,7 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve
#ifdef HAVE_UTEMPTER #ifdef HAVE_UTEMPTER
/* update utmp if has been more than 30 seconds since heard from client */ /* update utmp if has been more than 30 seconds since heard from client */
if ( connected_utmp if ( connected_utmp && time_since_remote_state > 30000 ) {
&& time_since_remote_state > 30000 ) {
utempter_remove_record( host_fd ); utempter_remove_record( host_fd );
char tmp[64]; char tmp[64];
@@ -936,9 +940,9 @@ static void serve( int host_fd, int pipe_fd, Terminal::Complete &terminal, Serve
network.set_current_state( terminal ); network.set_current_state( terminal );
} }
if ( !network.get_remote_state_num() if ( !network.get_remote_state_num() && time_since_remote_state >= timeout_if_no_client ) {
&& time_since_remote_state >= timeout_if_no_client ) { fprintf( stderr,
fprintf( stderr, "No connection within %llu seconds.\n", "No connection within %llu seconds.\n",
static_cast<unsigned long long>( timeout_if_no_client / 1000 ) ); static_cast<unsigned long long>( timeout_if_no_client / 1000 ) );
break; break;
} }
@@ -1040,15 +1044,11 @@ static void warn_unattached( const std::string & ignore_entry )
std::vector<std::string> unattached_mosh_servers; std::vector<std::string> unattached_mosh_servers;
while ( struct utmpx* entry = getutxent() ) { while ( struct utmpx* entry = getutxent() ) {
if ( (entry->ut_type == USER_PROCESS) if ( ( entry->ut_type == USER_PROCESS ) && ( username == std::string( entry->ut_user ) ) ) {
&& (username == std::string( entry->ut_user )) ) {
/* does line show unattached mosh session */ /* does line show unattached mosh session */
std::string text( entry->ut_host ); std::string text( entry->ut_host );
if ( (text.size() >= 5) if ( ( text.size() >= 5 ) && ( text.substr( 0, 5 ) == "mosh " ) && ( text[text.size() - 1] == ']' )
&& (text.substr( 0, 5 ) == "mosh ") && ( text != ignore_entry ) && device_exists( entry->ut_line ) ) {
&& (text[ text.size() - 1 ] == ']')
&& (text != ignore_entry)
&& device_exists( entry->ut_line ) ) {
unattached_mosh_servers.push_back( text ); unattached_mosh_servers.push_back( text );
} }
} }
@@ -1070,7 +1070,8 @@ static void warn_unattached( const std::string & ignore_entry )
} }
printf( "\033[37;44mMosh: You have %d detached Mosh sessions on this server, with PIDs:\n%s\033[m\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 */ #endif /* HAVE_UTMPX_H */
} }
+38 -34
View File
@@ -52,15 +52,15 @@
#include <util.h> #include <util.h>
#endif #endif
#include "stmclient.h"
#include "src/util/swrite.h"
#include "src/statesync/completeterminal.h" #include "src/statesync/completeterminal.h"
#include "src/statesync/user.h" #include "src/statesync/user.h"
#include "src/util/fatal_assert.h" #include "src/util/fatal_assert.h"
#include "src/util/locale_utils.h" #include "src/util/locale_utils.h"
#include "src/util/pty_compat.h" #include "src/util/pty_compat.h"
#include "src/util/select.h" #include "src/util/select.h"
#include "src/util/swrite.h"
#include "src/util/timestamp.h" #include "src/util/timestamp.h"
#include "stmclient.h"
#include "src/network/networktransport-impl.h" #include "src/network/networktransport-impl.h"
@@ -85,10 +85,12 @@ void STMClient::init( void )
LocaleVar native_ctype = get_ctype(); LocaleVar native_ctype = get_ctype();
std::string native_charset( locale_charset() ); 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" "Unfortunately, the client's environment (%s) specifies\n"
"the character set \"%s\".\n\n", "the character set \"%s\".\n\n",
native_ctype.str().c_str(), native_charset.c_str() ); native_ctype.str().c_str(),
native_charset.c_str() );
int unused __attribute( ( unused ) ) = system( "locale" ); int unused __attribute( ( unused ) ) = system( "locale" );
exit( 1 ); exit( 1 );
} }
@@ -166,7 +168,8 @@ void STMClient::init( void )
/* There are so many better ways to shoot oneself into leg than /* 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 setting escape key to Ctrl-C, Ctrl-D, NewLine, Ctrl-L or CarriageReturn
that we just won't allow that. */ 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_key = 0x1E;
escape_pass_key = '^'; escape_pass_key = '^';
escape_pass_key2 = '^'; escape_pass_key2 = '^';
@@ -189,7 +192,8 @@ void STMClient::init( void )
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 ); tmp = std::string( escape_key_name_buf );
std::wstring escape_key_name = std::wstring( tmp.begin(), tmp.end() ); 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; 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 ); overlays.get_notification_engine().set_escape_key_string( tmp );
} }
wchar_t tmp[128]; wchar_t tmp[128];
@@ -214,13 +218,18 @@ void STMClient::shutdown( void )
} }
if ( still_connecting() ) { 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" "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" "(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 ) { } else if ( network && !clean_shutdown ) {
fputs( "\n\nmosh did not shut down cleanly. Please note that the\n" 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 );
} }
} }
@@ -276,9 +285,7 @@ void STMClient::output_new_frame( void )
overlays.apply( new_state ); overlays.apply( new_state );
/* calculate minimal difference from where we are */ /* calculate minimal difference from where we are */
const std::string diff( display.new_frame( !repaint_requested, const std::string diff( display.new_frame( !repaint_requested, local_framebuffer, new_state ) );
local_framebuffer,
new_state ) );
swrite( STDOUT_FILENO, diff.data(), diff.size() ); swrite( STDOUT_FILENO, diff.data(), diff.size() );
repaint_requested = false; repaint_requested = false;
@@ -296,7 +303,8 @@ void STMClient::process_network_input( void )
overlays.get_prediction_engine().set_local_frame_acked( network->get_sent_state_acked() ); 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_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 ) bool STMClient::process_user_input( int fd )
@@ -336,7 +344,8 @@ bool STMClient::process_user_input( int fd )
if ( quit_sequence_started ) { if ( quit_sequence_started ) {
if ( the_byte == '.' ) { /* Quit sequence is Ctrl-^ . */ if ( the_byte == '.' ) { /* Quit sequence is Ctrl-^ . */
if ( net.has_remote_addr() && ( !net.shutdown_in_progress() ) ) { if ( net.has_remote_addr() && ( !net.shutdown_in_progress() ) ) {
overlays.get_notification_engine().set_notification_string( std::wstring( L"Exiting on user request..." ), true ); overlays.get_notification_engine().set_notification_string( std::wstring( L"Exiting on user request..." ),
true );
net.start_shutdown(); net.start_shutdown();
return true; return true;
} }
@@ -377,14 +386,16 @@ bool STMClient::process_user_input( int fd )
continue; 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 ) { if ( quit_sequence_started ) {
lf_entered = false; lf_entered = false;
overlays.get_notification_engine().set_notification_string( escape_key_help, true, false ); overlays.get_notification_engine().set_notification_string( escape_key_help, true, false );
continue; 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 */ if ( the_byte == 0x0C ) { /* Ctrl-L */
repaint_requested = true; repaint_requested = true;
@@ -451,9 +462,7 @@ bool STMClient::main( void )
/* network->fd() can in theory change over time */ /* network->fd() can in theory change over time */
sel.clear_fds(); sel.clear_fds();
std::vector<int> fd_list( network->fds() ); std::vector<int> fd_list( network->fds() );
for ( std::vector< int >::const_iterator it = fd_list.begin(); for ( std::vector<int>::const_iterator it = fd_list.begin(); it != fd_list.end(); it++ ) {
it != fd_list.end();
it++ ) {
sel.add_fd( *it ); sel.add_fd( *it );
} }
sel.add_fd( STDIN_FILENO ); sel.add_fd( STDIN_FILENO );
@@ -466,9 +475,7 @@ bool STMClient::main( void )
bool network_ready_to_read = false; bool network_ready_to_read = false;
for ( std::vector< int >::const_iterator it = fd_list.begin(); for ( std::vector<int>::const_iterator it = fd_list.begin(); it != fd_list.end(); it++ ) {
it != fd_list.end();
it++ ) {
if ( sel.read( *it ) ) { if ( sel.read( *it ) ) {
/* packet received from the network */ /* packet received from the network */
/* we only read one socket each run */ /* we only read one socket each run */
@@ -480,7 +487,8 @@ bool STMClient::main( void )
process_network_input(); 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() ) { if ( !network->has_remote_addr() ) {
break; break;
} else if ( !network->shutdown_in_progress() ) { } else if ( !network->shutdown_in_progress() ) {
@@ -497,15 +505,13 @@ bool STMClient::main( void )
resume(); resume();
} }
if ( sel.signal( SIGTERM ) if ( sel.signal( SIGTERM ) || sel.signal( SIGINT ) || sel.signal( SIGHUP ) || sel.signal( SIGPIPE ) ) {
|| sel.signal( SIGINT )
|| sel.signal( SIGHUP )
|| sel.signal( SIGPIPE ) ) {
/* shutdown signal */ /* shutdown signal */
if ( !network->has_remote_addr() ) { if ( !network->has_remote_addr() ) {
break; break;
} else if ( !network->shutdown_in_progress() ) { } 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(); network->start_shutdown();
} }
} }
@@ -528,20 +534,19 @@ bool STMClient::main( void )
} }
/* write diagnostic message if can't reach server */ /* write diagnostic message if can't reach server */
if ( still_connecting() if ( still_connecting() && ( !network->shutdown_in_progress() )
&& (!network->shutdown_in_progress())
&& ( timestamp() - network->get_latest_remote_state().timestamp > 250 ) ) { && ( timestamp() - network->get_latest_remote_state().timestamp > 250 ) ) {
if ( timestamp() - network->get_latest_remote_state().timestamp > 15000 ) { if ( timestamp() - network->get_latest_remote_state().timestamp > 15000 ) {
if ( !network->shutdown_in_progress() ) { 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(); network->start_shutdown();
} }
} else { } else {
overlays.get_notification_engine().set_notification_string( connecting_notification ); overlays.get_notification_engine().set_notification_string( connecting_notification );
} }
} else if ( ( network->get_remote_state_num() != 0 ) } else if ( ( network->get_remote_state_num() != 0 )
&& (overlays.get_notification_engine().get_notification_string() && ( overlays.get_notification_engine().get_notification_string() == connecting_notification ) ) {
== connecting_notification) ) {
overlays.get_notification_engine().set_notification_string( L"" ); overlays.get_notification_engine().set_notification_string( L"" );
} }
@@ -576,4 +581,3 @@ bool STMClient::main( void )
} }
return clean_shutdown; return clean_shutdown;
} }
+18 -23
View File
@@ -33,18 +33,19 @@
#ifndef STM_CLIENT_HPP #ifndef STM_CLIENT_HPP
#define STM_CLIENT_HPP #define STM_CLIENT_HPP
#include <string>
#include <memory> #include <memory>
#include <string>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <termios.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/frontend/terminaloverlay.h"
#include "src/network/networktransport.h"
#include "src/statesync/completeterminal.h"
#include "src/statesync/user.h"
class STMClient { class STMClient
{
private: private:
std::string ip; std::string ip;
std::string port; std::string port;
@@ -88,24 +89,18 @@ private:
void resume( void ); /* restore state after SIGCONT */ void resume( void ); /* restore state after SIGCONT */
public: 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 ) STMClient( const char* s_ip,
: ip( s_ip ? s_ip : "" ), port( s_port ? s_port : "" ), const char* s_port,
key( s_key ? s_key : "" ), const char* s_key,
escape_key( 0x1E ), escape_pass_key( '^' ), escape_pass_key2( '^' ), const char* predict_mode,
escape_requires_lf( false ), escape_key_help( L"?" ), unsigned int s_verbose,
saved_termios(), raw_termios(), const char* predict_overwrite )
window_size(), : ip( s_ip ? s_ip : "" ), port( s_port ? s_port : "" ), key( s_key ? s_key : "" ), escape_key( 0x1E ),
local_framebuffer( 1, 1 ), escape_pass_key( '^' ), escape_pass_key2( '^' ), escape_requires_lf( false ), escape_key_help( L"?" ),
new_state( 1, 1 ), saved_termios(), raw_termios(), window_size(), local_framebuffer( 1, 1 ), new_state( 1, 1 ), overlays(),
overlays(), network(), display( true ), /* use TERM environment var to initialize display */
network(), connecting_notification(), repaint_requested( false ), lf_entered( false ), quit_sequence_started( false ),
display( true ), /* use TERM environment var to initialize display */ clean_shutdown( false ), verbose( s_verbose )
connecting_notification(),
repaint_requested( false ),
lf_entered( false ),
quit_sequence_started( false ),
clean_shutdown( false ),
verbose( s_verbose )
{ {
if ( predict_mode ) { if ( predict_mode ) {
if ( !strcmp( predict_mode, "always" ) ) { if ( !strcmp( predict_mode, "always" ) ) {
+48 -88
View File
@@ -42,9 +42,7 @@ 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) if ( ( !active ) || ( row >= fb.ds.get_height() ) || ( col >= fb.ds.get_width() ) ) {
|| (row >= fb.ds.get_height())
|| (col >= fb.ds.get_width()) ) {
return; return;
} }
@@ -71,7 +69,8 @@ void ConditionalOverlayCell::apply( Framebuffer &fb, uint64_t confirmed_epoch, i
} }
} }
Validity ConditionalOverlayCell::get_validity( const Framebuffer &fb, int row, Validity ConditionalOverlayCell::get_validity( const Framebuffer& fb,
int row,
uint64_t early_ack __attribute__( ( unused ) ), uint64_t early_ack __attribute__( ( unused ) ),
uint64_t late_ack ) const uint64_t late_ack ) const
{ {
@@ -79,8 +78,7 @@ Validity ConditionalOverlayCell::get_validity( const Framebuffer &fb, int row,
return Inactive; return Inactive;
} }
if ( (row >= fb.ds.get_height()) if ( ( row >= fb.ds.get_height() ) || ( col >= fb.ds.get_width() ) ) {
|| (col >= fb.ds.get_width()) ) {
return IncorrectOrExpired; return IncorrectOrExpired;
} }
@@ -121,15 +119,13 @@ Validity ConditionalCursorMove::get_validity( const Framebuffer &fb,
return Inactive; return Inactive;
} }
if ( (row >= fb.ds.get_height()) if ( ( row >= fb.ds.get_height() ) || ( col >= fb.ds.get_width() ) ) {
|| (col >= fb.ds.get_width()) ) {
// fprintf( stderr, "Crazy cursor (%d,%d)!\n", row, col ); // fprintf( stderr, "Crazy cursor (%d,%d)!\n", row, col );
return IncorrectOrExpired; return IncorrectOrExpired;
} }
if ( late_ack >= expiration_frame ) { if ( late_ack >= expiration_frame ) {
if ( (fb.ds.get_cursor_col() == col) if ( ( fb.ds.get_cursor_col() == col ) && ( fb.ds.get_cursor_row() == row ) ) {
&& (fb.ds.get_cursor_row() == row) ) {
return Correct; return Correct;
} }
return IncorrectOrExpired; return IncorrectOrExpired;
@@ -157,24 +153,19 @@ void ConditionalCursorMove::apply( Framebuffer &fb, uint64_t confirmed_epoch ) c
} }
NotificationEngine::NotificationEngine() NotificationEngine::NotificationEngine()
: last_word_from_server( timestamp() ), : last_word_from_server( timestamp() ), last_acked_state( timestamp() ), escape_key_string(), message(),
last_acked_state( timestamp() ), message_is_network_error( false ), message_expiration( -1 ), show_quit_keystroke( true )
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 ) { static std::string human_readable_duration( int num_seconds, const std::string& seconds_abbr )
{
char tmp[128]; char tmp[128];
if ( num_seconds < 60 ) { if ( num_seconds < 60 ) {
snprintf( tmp, 128, "%d %s", num_seconds, seconds_abbr.c_str() ); snprintf( tmp, 128, "%d %s", num_seconds, seconds_abbr.c_str() );
} else if ( num_seconds < 3600 ) { } else if ( num_seconds < 3600 ) {
snprintf( tmp, 128, "%d:%02d", num_seconds / 60, num_seconds % 60 ); snprintf( tmp, 128, "%d:%02d", num_seconds / 60, num_seconds % 60 );
} else { } else {
snprintf( tmp, 128, "%d:%02d:%02d", num_seconds / 3600, snprintf( tmp, 128, "%d:%02d:%02d", num_seconds / 3600, ( num_seconds / 60 ) % 60, num_seconds % 60 );
(num_seconds / 60) % 60, num_seconds % 60 );
} }
return tmp; return tmp;
} }
@@ -235,17 +226,22 @@ void NotificationEngine::apply( Framebuffer &fb ) const
return; return;
} }
if ( message.empty() && time_expired ) { if ( message.empty() && time_expired ) {
swprintf( tmp, 128, L"mosh: Last %s %s ago.%s", explanation, swprintf( tmp,
human_readable_duration( static_cast<int>( time_elapsed ), 128,
"seconds" ).c_str(), L"mosh: Last %s %s ago.%s",
explanation,
human_readable_duration( static_cast<int>( time_elapsed ), "seconds" ).c_str(),
keystroke_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 ); swprintf( tmp, 128, L"mosh: %ls%s", message.c_str(), keystroke_str );
} else { } else {
swprintf( tmp, 128, L"mosh: %ls (%s without %s.)%s", message.c_str(), swprintf( tmp,
human_readable_duration( static_cast<int>( time_elapsed ), 128,
"s" ).c_str(), L"mosh: %ls (%s without %s.)%s",
explanation, keystroke_str ); message.c_str(),
human_readable_duration( static_cast<int>( time_elapsed ), "s" ).c_str(),
explanation,
keystroke_str );
} }
std::wstring string_to_draw( tmp ); std::wstring string_to_draw( tmp );
@@ -346,31 +342,24 @@ void TitleEngine::set_prefix( const std::wstring &s )
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(); for ( overlay_cells_type::const_iterator it = overlay_cells.begin(); it != overlay_cells.end(); it++ ) {
it != overlay_cells.end();
it++ ) {
it->apply( fb, confirmed_epoch, row_num, flag ); 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 if ( ( display_preference == Never )
|| glitch_trigger || !( srtt_trigger || glitch_trigger || ( display_preference == Always )
|| (display_preference == Always)
|| ( display_preference == Experimental ) ) ) { || ( display_preference == Experimental ) ) ) {
return; return;
} }
for ( cursors_type::const_iterator it = cursors.begin(); for ( cursors_type::const_iterator it = cursors.begin(); it != cursors.end(); it++ ) {
it != cursors.end();
it++ ) {
it->apply( fb, confirmed_epoch ); it->apply( fb, confirmed_epoch );
} }
for ( overlays_type::const_iterator it = overlays.begin(); for ( overlays_type::const_iterator it = overlays.begin(); it != overlays.end(); it++ ) {
it != overlays.end();
it++ ) {
it->apply( fb, confirmed_epoch, flagging ); it->apply( fb, confirmed_epoch, flagging );
} }
} }
@@ -386,18 +375,12 @@ void PredictionEngine::kill_epoch( uint64_t epoch, const Framebuffer &fb )
it = it_next; it = it_next;
} }
cursors.push_back( ConditionalCursorMove( local_frame_sent + 1, cursors.push_back( ConditionalCursorMove(
fb.ds.get_cursor_row(), local_frame_sent + 1, fb.ds.get_cursor_row(), fb.ds.get_cursor_col(), prediction_epoch ) );
fb.ds.get_cursor_col(),
prediction_epoch ) );
cursor().active = true; cursor().active = true;
for ( overlays_type::iterator i = overlays.begin(); for ( overlays_type::iterator i = overlays.begin(); i != overlays.end(); i++ ) {
i != overlays.end(); for ( overlay_cells_type::iterator j = i->overlay_cells.begin(); j != i->overlay_cells.end(); j++ ) {
i++ ) {
for ( overlay_cells_type::iterator j = i->overlay_cells.begin();
j != i->overlay_cells.end();
j++ ) {
if ( j->tentative( epoch - 1 ) ) { if ( j->tentative( epoch - 1 ) ) {
j->reset(); j->reset();
} }
@@ -421,17 +404,13 @@ void PredictionEngine::init_cursor( const Framebuffer &fb )
if ( cursors.empty() ) { if ( cursors.empty() ) {
/* initialize new cursor prediction */ /* initialize new cursor prediction */
cursors.push_back( ConditionalCursorMove( local_frame_sent + 1, cursors.push_back( ConditionalCursorMove(
fb.ds.get_cursor_row(), local_frame_sent + 1, fb.ds.get_cursor_row(), fb.ds.get_cursor_col(), prediction_epoch ) );
fb.ds.get_cursor_col(),
prediction_epoch ) );
cursor().active = true; cursor().active = true;
} else if ( cursor().tentative_until_epoch != prediction_epoch ) { } else if ( cursor().tentative_until_epoch != prediction_epoch ) {
cursors.push_back( ConditionalCursorMove( local_frame_sent + 1, cursors.push_back(
cursor().row, ConditionalCursorMove( local_frame_sent + 1, cursor().row, cursor().col, prediction_epoch ) );
cursor().col,
prediction_epoch ) );
cursor().active = true; cursor().active = true;
} }
@@ -443,8 +422,7 @@ void PredictionEngine::cull( const Framebuffer &fb )
return; return;
} }
if ( (last_height != fb.ds.get_height()) if ( ( last_height != fb.ds.get_height() ) || ( last_width != fb.ds.get_width() ) ) {
|| (last_width != fb.ds.get_width()) ) {
last_height = fb.ds.get_height(); last_height = fb.ds.get_height();
last_width = fb.ds.get_width(); last_width = fb.ds.get_width();
reset(); reset();
@@ -455,8 +433,7 @@ void PredictionEngine::cull( const Framebuffer &fb )
/* control srtt_trigger with hysteresis */ /* control srtt_trigger with hysteresis */
if ( send_interval > SRTT_TRIGGER_HIGH ) { if ( send_interval > SRTT_TRIGGER_HIGH ) {
srtt_trigger = true; srtt_trigger = true;
} else if ( srtt_trigger && } else if ( srtt_trigger && ( send_interval <= SRTT_TRIGGER_LOW ) /* 20 ms is current minimum value */
(send_interval <= SRTT_TRIGGER_LOW) /* 20 ms is current minimum value */
&& ( !active() ) ) { /* only turn off when no predictions being shown */ && ( !active() ) ) { /* only turn off when no predictions being shown */
srtt_trigger = false; srtt_trigger = false;
} }
@@ -485,11 +462,8 @@ void PredictionEngine::cull( const Framebuffer &fb )
continue; continue;
} }
for ( overlay_cells_type::iterator j = i->overlay_cells.begin(); for ( overlay_cells_type::iterator j = i->overlay_cells.begin(); j != i->overlay_cells.end(); j++ ) {
j != i->overlay_cells.end(); switch ( j->get_validity( fb, i->row_num, local_frame_acked, local_frame_late_acked ) ) {
j++ ) {
switch ( j->get_validity( fb, i->row_num,
local_frame_acked, local_frame_late_acked ) ) {
case IncorrectOrExpired: case IncorrectOrExpired:
if ( j->tentative( confirmed_epoch ) ) { if ( j->tentative( confirmed_epoch ) ) {
@@ -548,7 +522,6 @@ void PredictionEngine::cull( const Framebuffer &fb )
j->replacement.debug_contents(), i->row_num, j->col, j->replacement.debug_contents(), i->row_num, j->col,
confirmed_epoch, prediction_epoch ); confirmed_epoch, prediction_epoch );
*/ */
} }
/* When predictions come in quickly, slowly take away the glitch trigger. */ /* When predictions come in quickly, slowly take away the glitch trigger. */
@@ -561,9 +534,7 @@ void PredictionEngine::cull( const Framebuffer &fb )
/* match rest of row to the actual renditions */ /* match rest of row to the actual renditions */
{ {
const Renditions& actual_renditions = fb.get_cell( i->row_num, j->col )->get_renditions(); const Renditions& actual_renditions = fb.get_cell( i->row_num, j->col )->get_renditions();
for ( overlay_cells_type::iterator k = j; for ( overlay_cells_type::iterator k = j; k != i->overlay_cells.end(); k++ ) {
k != i->overlay_cells.end();
k++ ) {
k->replacement.get_renditions() = actual_renditions; k->replacement.get_renditions() = actual_renditions;
} }
} }
@@ -594,8 +565,7 @@ void PredictionEngine::cull( const Framebuffer &fb )
/* go through cursor predictions */ /* go through cursor predictions */
if ( !cursors.empty() if ( !cursors.empty()
&& cursor().get_validity( fb, && cursor().get_validity( fb, local_frame_acked, local_frame_late_acked ) == IncorrectOrExpired ) {
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", fprintf( stderr, "Sadly, we're predicting (%d,%d) vs. (%d,%d) [tau: %ld, expiration_time=%ld, now=%ld]\n",
cursor().row, cursor().col, 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. /* NB: switching from list to another STL container could break this code.
So we don't use the cursors_type typedef. */ So we don't use the cursors_type typedef. */
for ( std::list<ConditionalCursorMove>::iterator it = cursors.begin(); for ( std::list<ConditionalCursorMove>::iterator it = cursors.begin(); it != cursors.end(); ) {
it != cursors.end(); ) {
if ( it->get_validity( fb, local_frame_acked, local_frame_late_acked ) != Pending ) { if ( it->get_validity( fb, local_frame_acked, local_frame_late_acked ) != Pending ) {
it = cursors.erase( it ); it = cursors.erase( it );
} else { } else {
@@ -663,8 +632,7 @@ void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
uint64_t now = timestamp(); uint64_t now = timestamp();
/* translate application-mode cursor control function to ANSI cursor control sequence */ /* translate application-mode cursor control function to ANSI cursor control sequence */
if ( (last_byte == 0x1b) if ( ( last_byte == 0x1b ) && ( the_byte == 'O' ) ) {
&& (the_byte == 'O') ) {
the_byte = '['; the_byte = '[';
} }
last_byte = 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::Actions actions;
parser.input( the_byte, actions ); parser.input( the_byte, actions );
for ( Parser::Actions::iterator it = actions.begin(); for ( Parser::Actions::iterator it = actions.begin(); it != actions.end(); it++ ) {
it != actions.end();
it++ ) {
Parser::Action& act = **it; Parser::Action& act = **it;
/* /*
@@ -885,9 +851,7 @@ void PredictionEngine::newline_carriage_return( const Framebuffer &fb )
/* make blank prediction for last row */ /* make blank prediction for last row */
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() );
for ( overlay_cells_type::iterator j = the_row.overlay_cells.begin(); for ( overlay_cells_type::iterator j = the_row.overlay_cells.begin(); j != the_row.overlay_cells.end(); j++ ) {
j != the_row.overlay_cells.end();
j++ ) {
j->active = true; j->active = true;
j->tentative_until_epoch = prediction_epoch; j->tentative_until_epoch = prediction_epoch;
j->expire( local_frame_sent + 1, now ); j->expire( local_frame_sent + 1, now );
@@ -916,12 +880,8 @@ bool PredictionEngine::active( void ) const
return true; return true;
} }
for ( overlays_type::const_iterator i = overlays.begin(); for ( overlays_type::const_iterator i = overlays.begin(); i != overlays.end(); i++ ) {
i != overlays.end(); for ( overlay_cells_type::const_iterator j = i->overlay_cells.begin(); j != i->overlay_cells.end(); j++ ) {
i++ ) {
for ( overlay_cells_type::const_iterator j = i->overlay_cells.begin();
j != i->overlay_cells.end();
j++ ) {
if ( j->active ) { if ( j->active ) {
return true; return true;
} }
+57 -49
View File
@@ -33,10 +33,10 @@
#ifndef TERMINAL_OVERLAY_HPP #ifndef TERMINAL_OVERLAY_HPP
#define TERMINAL_OVERLAY_HPP #define TERMINAL_OVERLAY_HPP
#include "src/terminal/terminalframebuffer.h"
#include "src/network/network.h" #include "src/network/network.h"
#include "src/network/transportsender.h" #include "src/network/transportsender.h"
#include "src/terminal/parser.h" #include "src/terminal/parser.h"
#include "src/terminal/terminalframebuffer.h"
#include <climits> #include <climits>
#include <vector> #include <vector>
@@ -45,7 +45,8 @@ namespace Overlay {
using namespace Terminal; using namespace Terminal;
using namespace Network; using namespace Network;
enum Validity { enum Validity
{
Pending, Pending,
Correct, Correct,
CorrectNoCredit, CorrectNoCredit,
@@ -53,7 +54,8 @@ namespace Overlay {
Inactive Inactive
}; };
class ConditionalOverlay { class ConditionalOverlay
{
public: public:
uint64_t expiration_frame; uint64_t expiration_frame;
int col; int col;
@@ -62,22 +64,27 @@ namespace Overlay {
uint64_t prediction_time; /* used to find long-pending predictions */ uint64_t prediction_time; /* used to find long-pending predictions */
ConditionalOverlay( uint64_t s_exp, int s_col, uint64_t s_tentative ) ConditionalOverlay( uint64_t s_exp, int s_col, uint64_t s_tentative )
: expiration_frame( s_exp ), col( s_col ), : expiration_frame( s_exp ), col( s_col ), active( false ), tentative_until_epoch( s_tentative ),
active( false ), prediction_time( uint64_t( -1 ) )
tentative_until_epoch( s_tentative ), prediction_time( uint64_t( -1 ) )
{} {}
virtual ~ConditionalOverlay() {} virtual ~ConditionalOverlay() {}
bool tentative( uint64_t confirmed_epoch ) const { return tentative_until_epoch > confirmed_epoch; } 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 ) 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 { class ConditionalCursorMove : public ConditionalOverlay
{
public: public:
int row; int row;
@@ -90,7 +97,8 @@ namespace Overlay {
{} {}
}; };
class ConditionalOverlayCell : public ConditionalOverlay { class ConditionalOverlayCell : public ConditionalOverlay
{
public: public:
Cell replacement; Cell replacement;
bool unknown; bool unknown;
@@ -102,14 +110,17 @@ namespace Overlay {
Validity get_validity( const Framebuffer& fb, int row, uint64_t early_ack, uint64_t late_ack ) 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 ) ConditionalOverlayCell( uint64_t s_exp, int s_col, uint64_t s_tentative )
: ConditionalOverlay( s_exp, s_col, s_tentative ), : ConditionalOverlay( s_exp, s_col, s_tentative ), replacement( 0 ), unknown( false ), original_contents()
replacement( 0 ),
unknown( false ),
original_contents()
{} {}
void reset( void ) { unknown = false; original_contents.clear(); ConditionalOverlay::reset(); } void reset( void )
void reset_with_orig( void ) { {
unknown = false;
original_contents.clear();
ConditionalOverlay::reset();
}
void reset_with_orig( void )
{
if ( ( !active ) || unknown ) { if ( ( !active ) || unknown ) {
reset(); reset();
return; return;
@@ -120,7 +131,8 @@ namespace Overlay {
} }
}; };
class ConditionalOverlayRow { class ConditionalOverlayRow
{
public: public:
int row_num; int row_num;
@@ -133,7 +145,8 @@ namespace Overlay {
}; };
/* the various overlays */ /* the various overlays */
class NotificationEngine { class NotificationEngine
{
private: private:
uint64_t last_word_from_server; uint64_t last_word_from_server;
uint64_t last_acked_state; uint64_t last_acked_state;
@@ -155,7 +168,9 @@ namespace Overlay {
void server_acked( uint64_t s_last_acked ) { last_acked_state = s_last_acked; } void server_acked( uint64_t s_last_acked ) { last_acked_state = s_last_acked; }
int wait_time( void ) const; 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; message = s_message;
if ( permanent ) { if ( permanent ) {
@@ -194,7 +209,8 @@ namespace Overlay {
NotificationEngine(); NotificationEngine();
}; };
class PredictionEngine { class PredictionEngine
{
private: private:
static const uint64_t SRTT_TRIGGER_LOW = 20; /* <= ms cures SRTT trigger to show predictions */ 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 */ static const uint64_t SRTT_TRIGGER_HIGH = 30; /* > ms starts SRTT trigger */
@@ -235,7 +251,11 @@ namespace Overlay {
unsigned int glitch_trigger; /* show predictions temporarily because of long-pending prediction */ unsigned int glitch_trigger; /* show predictions temporarily because of long-pending prediction */
uint64_t last_quick_confirmation; 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 );
@@ -246,7 +266,8 @@ namespace Overlay {
int last_height, last_width; int last_height, last_width;
public: public:
enum DisplayPreference { enum DisplayPreference
{
Always, Always,
Never, Never,
Adaptive, Adaptive,
@@ -259,7 +280,8 @@ namespace Overlay {
bool active( void ) const; 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? */ /* Are there any timing-based triggers that haven't fired yet? */
return !( glitch_trigger && flagging ); return !( glitch_trigger && flagging );
} }
@@ -280,30 +302,18 @@ namespace Overlay {
void set_send_interval( unsigned int x ) { send_interval = x; } void set_send_interval( unsigned int x ) { send_interval = x; }
int wait_time( void ) const int wait_time( void ) const { return ( timing_tests_necessary() && active() ) ? 50 : INT_MAX; }
{
return ( timing_tests_necessary() && active() )
? 50
: INT_MAX;
}
PredictionEngine( void ) : last_byte( 0 ), parser(), overlays(), cursors(), PredictionEngine( void )
local_frame_sent( 0 ), local_frame_acked( 0 ), : last_byte( 0 ), parser(), overlays(), cursors(), local_frame_sent( 0 ), local_frame_acked( 0 ),
local_frame_late_acked( 0 ), local_frame_late_acked( 0 ), prediction_epoch( 1 ), confirmed_epoch( 0 ), flagging( false ),
prediction_epoch( 1 ), confirmed_epoch( 0 ), srtt_trigger( false ), glitch_trigger( 0 ), last_quick_confirmation( 0 ), send_interval( 250 ),
flagging( false ), last_height( 0 ), last_width( 0 ), display_preference( Adaptive ), predict_overwrite( 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 { class TitleEngine
{
private: private:
Terminal::Framebuffer::title_type prefix; Terminal::Framebuffer::title_type prefix;
@@ -314,7 +324,8 @@ namespace Overlay {
}; };
/* the overlay manager */ /* the overlay manager */
class OverlayManager { class OverlayManager
{
private: private:
NotificationEngine notifications; NotificationEngine notifications;
PredictionEngine predictions; PredictionEngine predictions;
@@ -330,10 +341,7 @@ namespace Overlay {
OverlayManager() : notifications(), predictions(), title() {} OverlayManager() : notifications(), predictions(), title() {}
int wait_time( void ) const int wait_time( void ) const { return std::min( notifications.wait_time(), predictions.wait_time() ); }
{
return std::min( notifications.wait_time(), predictions.wait_time() );
}
}; };
} }
+3 -2
View File
@@ -1,10 +1,11 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include "src/terminal/parser.h"
#include "src/statesync/completeterminal.h" #include "src/statesync/completeterminal.h"
#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 )
{
Terminal::Display display( false ); Terminal::Display display( false );
Terminal::Complete complete( 80, 24 ); Terminal::Complete complete( 80, 24 );
Terminal::Framebuffer state( 80, 24 ); Terminal::Framebuffer state( 80, 24 );
+2 -1
View File
@@ -3,7 +3,8 @@
#include "src/terminal/parser.h" #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::UTF8Parser parser;
Parser::Actions result; Parser::Actions result;
+4 -6
View File
@@ -40,18 +40,16 @@ 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; long unsigned int len = BUFFER_SIZE;
dos_assert( Z_OK == compress( buffer, &len, dos_assert( Z_OK
reinterpret_cast<const unsigned char *>( input.data() ), == compress( buffer, &len, reinterpret_cast<const unsigned char*>( input.data() ), input.size() ) );
input.size() ) );
return std::string( reinterpret_cast<char*>( buffer ), len ); 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; long unsigned int len = BUFFER_SIZE;
dos_assert( Z_OK == uncompress( buffer, &len, dos_assert( Z_OK
reinterpret_cast<const unsigned char *>( input.data() ), == uncompress( buffer, &len, reinterpret_cast<const unsigned char*>( input.data() ), input.size() ) );
input.size() ) );
return std::string( reinterpret_cast<char*>( buffer ), len ); return std::string( reinterpret_cast<char*>( buffer ), len );
} }
+2 -1
View File
@@ -36,7 +36,8 @@
#include <string> #include <string>
namespace Network { namespace Network {
class Compressor { class Compressor
{
private: private:
static const int BUFFER_SIZE = 2048 * 2048; /* effective limit on terminal size */ static const int BUFFER_SIZE = 2048 * 2048; /* effective limit on terminal size */
+59 -93
View File
@@ -36,8 +36,8 @@
#include <cerrno> #include <cerrno>
#include <cstring> #include <cstring>
#include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/types.h>
#ifdef HAVE_SYS_UIO_H #ifdef HAVE_SYS_UIO_H
#include <sys/uio.h> #include <sys/uio.h>
#endif #endif
@@ -45,11 +45,11 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <unistd.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/dos_assert.h"
#include "src/util/fatal_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" #include "src/util/timestamp.h"
@@ -70,10 +70,8 @@ const uint64_t SEQUENCE_MASK = uint64_t(-1) ^ DIRECTION_MASK;
/* Read in packet */ /* Read in packet */
Packet::Packet( const Message& message ) Packet::Packet( const Message& message )
: seq( message.nonce.val() & SEQUENCE_MASK ), : seq( message.nonce.val() & SEQUENCE_MASK ),
direction( (message.nonce.val() & DIRECTION_MASK) ? TO_CLIENT : TO_SERVER ), direction( ( message.nonce.val() & DIRECTION_MASK ) ? TO_CLIENT : TO_SERVER ), timestamp( -1 ),
timestamp( -1 ), timestamp_reply( -1 ), payload()
timestamp_reply( -1 ),
payload()
{ {
dos_assert( message.text.size() >= 2 * sizeof( uint16_t ) ); dos_assert( message.text.size() >= 2 * sizeof( uint16_t ) );
@@ -89,8 +87,8 @@ 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 ) ), uint16_t ts_net[2]
static_cast<uint16_t>( htobe16( timestamp_reply ) ) }; = { 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 ) );
@@ -149,8 +147,7 @@ void Connection::prune_sockets( void )
} }
} }
Connection::Socket::Socket( int family ) Connection::Socket::Socket( int family ) : _fd( socket( family, SOCK_DGRAM, 0 ) )
: _fd( socket( family, SOCK_DGRAM, 0 ) )
{ {
if ( _fd < 0 ) { if ( _fd < 0 ) {
throw NetworkException( "socket", errno ); throw NetworkException( "socket", errno );
@@ -189,9 +186,7 @@ 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(); for ( std::deque<Socket>::const_iterator it = socks.begin(); it != socks.end(); it++ ) {
it != socks.end();
it++ ) {
ret.push_back( it->fd() ); ret.push_back( it->fd() );
} }
@@ -212,43 +207,31 @@ void Connection::set_MTU( int family )
} }
} }
class AddrInfo { class AddrInfo
{
public: public:
struct addrinfo* res; struct addrinfo* res;
AddrInfo( const char *node, const char *service, AddrInfo( const char* node, const char* service, const struct addrinfo* hints ) : res( NULL )
const struct addrinfo *hints ) : {
res( NULL ) {
int errcode = getaddrinfo( node, service, hints, &res ); int errcode = getaddrinfo( node, service, hints, &res );
if ( errcode != 0 ) { 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: private:
AddrInfo( const AddrInfo& ); AddrInfo( const AddrInfo& );
AddrInfo& operator=( const AddrInfo& ); AddrInfo& operator=( const AddrInfo& );
}; };
Connection::Connection( const char* desired_ip, const char* desired_port ) /* server */ Connection::Connection( const char* desired_ip, const char* desired_port ) /* server */
: socks(), : socks(), has_remote_addr( false ), remote_addr(), remote_addr_len( 0 ), server( true ), MTU( DEFAULT_SEND_MTU ),
has_remote_addr( false ), key(), session( key ), direction( TO_CLIENT ), saved_timestamp( -1 ), saved_timestamp_received_at( 0 ),
remote_addr(), expected_receiver_seq( 0 ), last_heard( -1 ), last_port_choice( -1 ), last_roundtrip_success( -1 ),
remote_addr_len( 0 ), RTT_hit( false ), SRTT( 1000 ), RTTVAR( 500 ), send_error()
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(); setup();
@@ -269,20 +252,21 @@ Connection::Connection( const char *desired_ip, const char *desired_port ) /* se
/* try to bind to desired IP first */ /* try to bind to desired IP first */
if ( desired_ip ) { if ( desired_ip ) {
try { try {
if ( try_bind( desired_ip, desired_port_low, desired_port_high ) ) { return; } if ( try_bind( desired_ip, desired_port_low, desired_port_high ) ) {
return;
}
} catch ( const NetworkException& e ) { } catch ( const NetworkException& e ) {
fprintf( stderr, "Error binding to IP %s: %s\n", fprintf( stderr, "Error binding to IP %s: %s\n", desired_ip, e.what() );
desired_ip,
e.what() );
} }
} }
/* now try any local interface */ /* now try any local interface */
try { try {
if ( try_bind( NULL, desired_port_low, desired_port_high ) ) { return; } if ( try_bind( NULL, desired_port_low, desired_port_high ) ) {
return;
}
} catch ( const NetworkException& e ) { } catch ( const NetworkException& e ) {
fprintf( stderr, "Error binding to any interface: %s\n", fprintf( stderr, "Error binding to any interface: %s\n", e.what() );
e.what() );
throw; /* this time it's fatal */ throw; /* this time it's fatal */
} }
@@ -340,37 +324,25 @@ bool Connection::try_bind( const char *addr, int port_low, int port_high )
int saved_errno = errno; int saved_errno = errno;
socks.pop_back(); socks.pop_back();
char host[NI_MAXHOST], serv[NI_MAXSERV]; char host[NI_MAXHOST], serv[NI_MAXSERV];
int errcode = getnameinfo( &local_addr.sa, local_addr_len, int errcode = getnameinfo( &local_addr.sa,
host, sizeof( host ), serv, sizeof( serv ), local_addr_len,
host,
sizeof( host ),
serv,
sizeof( serv ),
NI_DGRAM | NI_NUMERICHOST | NI_NUMERICSERV ); NI_DGRAM | NI_NUMERICHOST | NI_NUMERICSERV );
if ( errcode != 0 ) { if ( errcode != 0 ) {
throw NetworkException( std::string( "bind: getnameinfo: " ) + gai_strerror( errcode ), 0 ); throw NetworkException( std::string( "bind: getnameinfo: " ) + gai_strerror( errcode ), 0 );
} }
fprintf( stderr, "Failed binding to %s:%s\n", fprintf( stderr, "Failed binding to %s:%s\n", host, serv );
host, serv );
throw NetworkException( "bind", saved_errno ); throw NetworkException( "bind", saved_errno );
} }
Connection::Connection( const char* key_str, const char* ip, const char* port ) /* client */ Connection::Connection( const char* key_str, const char* ip, const char* port ) /* client */
: socks(), : socks(), has_remote_addr( false ), remote_addr(), remote_addr_len( 0 ), server( false ),
has_remote_addr( false ), MTU( DEFAULT_SEND_MTU ), key( key_str ), session( key ), direction( TO_SERVER ), saved_timestamp( -1 ),
remote_addr(), saved_timestamp_received_at( 0 ), expected_receiver_seq( 0 ), last_heard( -1 ), last_port_choice( -1 ),
remote_addr_len( 0 ), last_roundtrip_success( -1 ), RTT_hit( false ), SRTT( 1000 ), RTTVAR( 500 ), send_error()
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(); setup();
@@ -402,8 +374,7 @@ void Connection::send( const std::string & s )
std::string p = session.encrypt( px.toMessage() ); std::string p = session.encrypt( px.toMessage() );
ssize_t bytes_sent = sendto( sock(), p.data(), p.size(), MSG_DONTWAIT, ssize_t bytes_sent = sendto( sock(), p.data(), p.size(), MSG_DONTWAIT, &remote_addr.sa, remote_addr_len );
&remote_addr.sa, remote_addr_len );
if ( bytes_sent != static_cast<ssize_t>( p.size() ) ) { if ( bytes_sent != static_cast<ssize_t>( p.size() ) ) {
/* Make sendto() failure available to the frontend. */ /* 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" ); fprintf( stderr, "Server now detached from client.\n" );
} }
} else { /* client */ } else { /* client */
if ( ( now - last_port_choice > PORT_HOP_INTERVAL ) if ( ( now - last_port_choice > PORT_HOP_INTERVAL ) && ( now - last_roundtrip_success > PORT_HOP_INTERVAL ) ) {
&& ( now - last_roundtrip_success > PORT_HOP_INTERVAL ) ) {
hop_port(); hop_port();
} }
} }
@@ -432,15 +402,12 @@ void Connection::send( const std::string & s )
std::string Connection::recv( void ) std::string Connection::recv( void )
{ {
assert( !socks.empty() ); assert( !socks.empty() );
for ( std::deque< Socket >::const_iterator it = socks.begin(); for ( std::deque<Socket>::const_iterator it = socks.begin(); it != socks.end(); it++ ) {
it != socks.end();
it++ ) {
std::string payload; std::string payload;
try { try {
payload = recv_one( it->fd() ); payload = recv_one( it->fd() );
} catch ( NetworkException& e ) { } catch ( NetworkException& e ) {
if ( (e.the_errno == EAGAIN) if ( ( e.the_errno == EAGAIN ) || ( e.the_errno == EWOULDBLOCK ) ) {
|| (e.the_errno == EWOULDBLOCK) ) {
continue; continue;
} else { } else {
throw; throw;
@@ -495,8 +462,7 @@ std::string Connection::recv_one( int sock_to_recv )
bool congestion_experienced = false; bool congestion_experienced = false;
struct cmsghdr* ecn_hdr = CMSG_FIRSTHDR( &header ); struct cmsghdr* ecn_hdr = CMSG_FIRSTHDR( &header );
if ( ecn_hdr if ( ecn_hdr && ecn_hdr->cmsg_level == IPPROTO_IP
&& ecn_hdr->cmsg_level == IPPROTO_IP
&& ( ecn_hdr->cmsg_type == IP_TOS && ( ecn_hdr->cmsg_type == IP_TOS
#ifdef IP_RECVTOS #ifdef IP_RECVTOS
|| ecn_hdr->cmsg_type == IP_RECVTOS || ecn_hdr->cmsg_type == IP_RECVTOS
@@ -513,7 +479,8 @@ std::string Connection::recv_one( int sock_to_recv )
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; return p.payload;
} }
expected_receiver_seq = p.seq + 1; /* this is security-sensitive because a replay attack could otherwise expected_receiver_seq = p.seq + 1; /* this is security-sensitive because a replay attack could otherwise
@@ -557,19 +524,22 @@ std::string Connection::recv_one( int sock_to_recv )
last_heard = timestamp(); last_heard = timestamp();
if ( server && /* only client can roam */ if ( server && /* only client can roam */
( remote_addr_len != header.msg_namelen || ( remote_addr_len != header.msg_namelen
memcmp( &remote_addr, &packet_remote_addr, remote_addr_len ) != 0 ) ) { || memcmp( &remote_addr, &packet_remote_addr, remote_addr_len ) != 0 ) ) {
remote_addr = packet_remote_addr; remote_addr = packet_remote_addr;
remote_addr_len = header.msg_namelen; remote_addr_len = header.msg_namelen;
char host[NI_MAXHOST], serv[NI_MAXSERV]; char host[NI_MAXHOST], serv[NI_MAXSERV];
int errcode = getnameinfo( &remote_addr.sa, remote_addr_len, int errcode = getnameinfo( &remote_addr.sa,
host, sizeof( host ), serv, sizeof( serv ), remote_addr_len,
host,
sizeof( host ),
serv,
sizeof( serv ),
NI_DGRAM | NI_NUMERICHOST | NI_NUMERICSERV ); NI_DGRAM | NI_NUMERICHOST | NI_NUMERICSERV );
if ( errcode != 0 ) { if ( errcode != 0 ) {
throw NetworkException( std::string( "recv_one: getnameinfo: " ) + gai_strerror( errcode ), 0 ); throw NetworkException( std::string( "recv_one: getnameinfo: " ) + gai_strerror( errcode ), 0 );
} }
fprintf( stderr, "Server now attached to client at %s:%s\n", fprintf( stderr, "Server now attached to client at %s:%s\n", host, serv );
host, serv );
} }
return p.payload; return p.payload;
} }
@@ -584,9 +554,7 @@ std::string Connection::port( void ) const
} }
char serv[NI_MAXSERV]; char serv[NI_MAXSERV];
int errcode = getnameinfo( &local_addr.sa, addrlen, int errcode = getnameinfo( &local_addr.sa, addrlen, NULL, 0, serv, sizeof( serv ), NI_DGRAM | NI_NUMERICSERV );
NULL, 0, serv, sizeof( serv ),
NI_DGRAM | NI_NUMERICSERV );
if ( errcode != 0 ) { if ( errcode != 0 ) {
throw NetworkException( std::string( "port: getnameinfo: " ) + gai_strerror( errcode ), 0 ); throw NetworkException( std::string( "port: getnameinfo: " ) + gai_strerror( errcode ), 0 );
} }
@@ -637,8 +605,7 @@ Connection::Socket::~Socket()
fatal_assert( close( _fd ) == 0 ); fatal_assert( close( _fd ) == 0 );
} }
Connection::Socket::Socket( const Socket & other ) Connection::Socket::Socket( const Socket& other ) : _fd( dup( other._fd ) )
: _fd( dup( other._fd ) )
{ {
if ( _fd < 0 ) { if ( _fd < 0 ) {
throw NetworkException( "socket", errno ); throw NetworkException( "socket", errno );
@@ -702,6 +669,5 @@ bool Connection::parse_portrange( const char * desired_port, int & desired_port_
return false; return false;
} }
return true; return true;
} }
+22 -16
View File
@@ -42,8 +42,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/socket.h>
#include "src/crypto/crypto.h" #include "src/crypto/crypto.h"
@@ -56,36 +56,40 @@ namespace Network {
uint16_t timestamp16( void ); uint16_t timestamp16( void );
uint16_t timestamp_diff( uint16_t tsnew, uint16_t tsold ); uint16_t timestamp_diff( uint16_t tsnew, uint16_t tsold );
class NetworkException : public std::exception { class NetworkException : public std::exception
{
public: public:
std::string function; std::string function;
int the_errno; int the_errno;
private: private:
std::string my_what; std::string my_what;
public: public:
NetworkException( std::string s_function = "<none>", int s_errno = 0 ) NetworkException( std::string s_function = "<none>", int s_errno = 0 )
: function( s_function ), the_errno( s_errno ), : function( s_function ), the_errno( s_errno ), my_what( function + ": " + strerror( the_errno ) )
my_what(function + ": " + strerror(the_errno)) {} {}
const char* what() const throw() { return my_what.c_str(); } const char* what() const throw() { return my_what.c_str(); }
~NetworkException() throw() {} ~NetworkException() throw() {}
}; };
enum Direction { enum Direction
{
TO_SERVER = 0, TO_SERVER = 0,
TO_CLIENT = 1 TO_CLIENT = 1
}; };
class Packet { class Packet
{
public: public:
const uint64_t seq; const uint64_t seq;
Direction direction; Direction direction;
uint16_t timestamp, timestamp_reply; uint16_t timestamp, timestamp_reply;
std::string payload; std::string payload;
Packet( Direction s_direction, Packet( Direction s_direction, uint16_t s_timestamp, uint16_t s_timestamp_reply, const std::string& s_payload )
uint16_t s_timestamp, uint16_t s_timestamp_reply, const std::string & s_payload ) : seq( Crypto::unique() ), direction( s_direction ), timestamp( s_timestamp ),
: seq( Crypto::unique() ), direction( s_direction ), timestamp_reply( s_timestamp_reply ), payload( s_payload )
timestamp( s_timestamp ), timestamp_reply( s_timestamp_reply ), payload( s_payload )
{} {}
Packet( const Message& message ); Packet( const Message& message );
@@ -100,7 +104,8 @@ namespace Network {
struct sockaddr_storage ss; struct sockaddr_storage ss;
}; };
class Connection { class Connection
{
private: private:
/* /*
* For IPv4, guess the typical (minimum) header length; * For IPv4, guess the typical (minimum) header length;
@@ -195,7 +200,11 @@ namespace Network {
void hop_port( void ); 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 ); void prune_sockets( void );
@@ -225,10 +234,7 @@ namespace Network {
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; } socklen_t get_remote_addr_len( void ) const { return remote_addr_len; }
std::string &get_send_error( void ) std::string& get_send_error( void ) { return send_error; }
{
return send_error;
}
void set_last_roundtrip_success( uint64_t s_success ) { last_roundtrip_success = s_success; } void set_last_roundtrip_success( uint64_t s_success ) { last_roundtrip_success = s_success; }
+31 -23
View File
@@ -40,29 +40,26 @@
using namespace Network; using namespace Network;
template<class MyState, class RemoteState> template<class MyState, class RemoteState>
Transport<MyState, RemoteState>::Transport( MyState &initial_state, RemoteState &initial_remote, Transport<MyState, RemoteState>::Transport( MyState& initial_state,
const char *desired_ip, const char *desired_port ) RemoteState& initial_remote,
: connection( desired_ip, desired_port ), const char* desired_ip,
sender( &connection, initial_state ), const char* desired_port )
: connection( desired_ip, desired_port ), sender( &connection, initial_state ),
received_states( 1, TimestampedState<RemoteState>( timestamp(), 0, initial_remote ) ), received_states( 1, TimestampedState<RemoteState>( timestamp(), 0, initial_remote ) ),
receiver_quench_timer( 0 ), receiver_quench_timer( 0 ), last_receiver_state( initial_remote ), fragments(), verbose( 0 )
last_receiver_state( initial_remote ),
fragments(),
verbose( 0 )
{ {
/* server */ /* server */
} }
template<class MyState, class RemoteState> template<class MyState, class RemoteState>
Transport<MyState, RemoteState>::Transport( MyState &initial_state, RemoteState &initial_remote, Transport<MyState, RemoteState>::Transport( MyState& initial_state,
const char *key_str, const char *ip, const char *port ) RemoteState& initial_remote,
: connection( key_str, ip, port ), const char* key_str,
sender( &connection, initial_state ), const char* ip,
const char* port )
: connection( key_str, ip, port ), sender( &connection, initial_state ),
received_states( 1, TimestampedState<RemoteState>( timestamp(), 0, initial_remote ) ), received_states( 1, TimestampedState<RemoteState>( timestamp(), 0, initial_remote ) ),
receiver_quench_timer( 0 ), receiver_quench_timer( 0 ), last_receiver_state( initial_remote ), fragments(), verbose( 0 )
last_receiver_state( initial_remote ),
fragments(),
verbose( 0 )
{ {
/* client */ /* client */
} }
@@ -106,7 +103,8 @@ void Transport<MyState, RemoteState>::recv( void )
} }
if ( !found ) { 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 */ 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(); uint64_t now = timestamp();
if ( now < receiver_quench_timer ) { /* deny letting state grow further */ if ( now < receiver_quench_timer ) { /* deny letting state grow further */
if ( verbose ) { if ( verbose ) {
fprintf( stderr, "[%u] Receiver queue full, discarding %d (malicious sender or long-unidirectional connectivity?)\n", fprintf(
(unsigned int)(timestamp() % 100000), (int)inst.new_num() ); stderr,
"[%u] Receiver queue full, discarding %d (malicious sender or long-unidirectional connectivity?)\n",
(unsigned int)( timestamp() % 100000 ),
(int)inst.new_num() );
} }
return; return;
} else { } else {
@@ -146,15 +147,22 @@ void Transport<MyState, RemoteState>::recv( void )
if ( i->num > new_state.num ) { if ( i->num > new_state.num ) {
received_states.insert( i, new_state ); received_states.insert( i, new_state );
if ( verbose ) { if ( verbose ) {
fprintf( stderr, "[%u] Received OUT-OF-ORDER state %d [ack %d]\n", fprintf( stderr,
(unsigned int)(timestamp() % 100000), (int)new_state.num, (int)inst.ack_num() ); "[%u] Received OUT-OF-ORDER state %d [ack %d]\n",
(unsigned int)( timestamp() % 100000 ),
(int)new_state.num,
(int)inst.ack_num() );
} }
return; return;
} }
} }
if ( verbose ) { if ( verbose ) {
fprintf( stderr, "[%u] Received state %d [coming from %d, ack %d]\n", fprintf( stderr,
(unsigned int)(timestamp() % 100000), (int)new_state.num, (int)inst.old_num(), (int)inst.ack_num() ); "[%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 ); received_states.push_back( new_state );
sender.set_ack_num( received_states.back().num ); sender.set_ack_num( received_states.back().num );
+14 -5
View File
@@ -65,10 +65,15 @@ namespace Network {
unsigned int verbose; unsigned int verbose;
public: public:
Transport( MyState &initial_state, RemoteState &initial_remote, Transport( MyState& initial_state,
const char *desired_ip, const char *desired_port ); RemoteState& initial_remote,
Transport( MyState &initial_state, RemoteState &initial_remote, const char* desired_ip,
const char *key_str, const char *ip, const char *port ); 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. */ /* Send data or an ack if necessary. */
void tick( void ) { sender.tick(); } void tick( void ) { sender.tick(); }
@@ -105,7 +110,11 @@ namespace Network {
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 ); } void set_send_delay( int new_delay ) { sender.set_send_delay( new_delay ); }
+10 -14
View File
@@ -32,11 +32,11 @@
#include <cassert> #include <cassert>
#include "src/crypto/byteorder.h"
#include "transportfragment.h"
#include "src/protobufs/transportinstruction.pb.h"
#include "compressor.h" #include "compressor.h"
#include "src/crypto/byteorder.h"
#include "src/protobufs/transportinstruction.pb.h"
#include "src/util/fatal_assert.h" #include "src/util/fatal_assert.h"
#include "transportfragment.h"
using namespace Network; using namespace Network;
using namespace TransportBuffers; using namespace TransportBuffers;
@@ -61,7 +61,8 @@ std::string Fragment::tostring( void )
ret += network_order_string( id ); 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; uint16_t combined_fragment_num = ( final << 15 ) | fragment_num;
ret += network_order_string( combined_fragment_num ); ret += network_order_string( combined_fragment_num );
@@ -73,8 +74,7 @@ std::string Fragment::tostring( void )
} }
Fragment::Fragment( const std::string& x ) Fragment::Fragment( const std::string& x )
: id( -1 ), fragment_num( -1 ), final( false ), initialized( true ), : id( -1 ), fragment_num( -1 ), final( false ), initialized( true ), contents()
contents()
{ {
fatal_assert( x.size() >= frag_header_len ); fatal_assert( x.size() >= frag_header_len );
contents = std::string( x.begin() + frag_header_len, x.end() ); contents = std::string( x.begin() + frag_header_len, x.end() );
@@ -100,8 +100,7 @@ bool FragmentAssembly::add_fragment( Fragment &frag )
current_id = frag.id; current_id = frag.id;
} else { /* not a new packet */ } else { /* not a new packet */
/* see if we already have this fragment */ /* see if we already have this fragment */
if ( (fragments.size() > frag.fragment_num) if ( ( fragments.size() > frag.fragment_num ) && ( fragments.at( frag.fragment_num ).initialized ) ) {
&& (fragments.at( frag.fragment_num ).initialized) ) {
/* make sure new version is same as what we already have */ /* make sure new version is same as what we already have */
assert( fragments.at( frag.fragment_num ) == frag ); assert( fragments.at( frag.fragment_num ) == frag );
} else { } else {
@@ -157,18 +156,15 @@ bool Fragment::operator==( const Fragment &x ) const
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; MTU -= Fragment::frag_header_len;
if ( (inst.old_num() != last_instruction.old_num()) if ( ( inst.old_num() != last_instruction.old_num() ) || ( inst.new_num() != last_instruction.new_num() )
|| (inst.new_num() != last_instruction.new_num())
|| ( inst.ack_num() != last_instruction.ack_num() ) || ( inst.ack_num() != last_instruction.ack_num() )
|| ( inst.throwaway_num() != last_instruction.throwaway_num() ) || ( inst.throwaway_num() != last_instruction.throwaway_num() )
|| ( inst.chaff() != last_instruction.chaff() ) || ( inst.chaff() != last_instruction.chaff() )
|| (inst.protocol_version() != last_instruction.protocol_version()) || ( inst.protocol_version() != last_instruction.protocol_version() ) || ( last_MTU != MTU ) ) {
|| (last_MTU != MTU) ) {
next_instruction_id++; next_instruction_id++;
} }
if ( (inst.old_num() == last_instruction.old_num()) if ( ( inst.old_num() == last_instruction.old_num() ) && ( inst.new_num() == last_instruction.new_num() ) ) {
&& (inst.new_num() == last_instruction.new_num()) ) {
assert( inst.diff() == last_instruction.diff() ); assert( inst.diff() == last_instruction.diff() );
} }
+2 -5
View File
@@ -55,13 +55,10 @@ namespace Network {
std::string contents; std::string contents;
Fragment() Fragment() : id( -1 ), fragment_num( -1 ), final( false ), initialized( false ), contents() {}
: 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 ) 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 ), : id( s_id ), fragment_num( s_fragment_num ), final( s_final ), initialized( true ), contents( s_contents )
contents( s_contents )
{} {}
Fragment( const std::string& x ); Fragment( const std::string& x );
+29 -39
View File
@@ -48,25 +48,13 @@ using namespace Network;
template<class MyState> template<class MyState>
TransportSender<MyState>::TransportSender( Connection* s_connection, MyState& initial_state ) TransportSender<MyState>::TransportSender( Connection* s_connection, MyState& initial_state )
: connection( s_connection ), : connection( s_connection ), current_state( initial_state ),
current_state( initial_state ),
sent_states( 1, TimestampedState<MyState>( timestamp(), 0, initial_state ) ), sent_states( 1, TimestampedState<MyState>( timestamp(), 0, initial_state ) ),
assumed_receiver_state( sent_states.begin() ), assumed_receiver_state( sent_states.begin() ), fragmenter(), next_ack_time( timestamp() ),
fragmenter(), next_send_time( timestamp() ), verbose( 0 ), shutdown_in_progress( false ), shutdown_tries( 0 ),
next_ack_time( timestamp() ), shutdown_start( -1 ), ack_num( 0 ), pending_data_ack( false ), SEND_MINDELAY( 8 ), last_heard( 0 ), prng(),
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 ) mindelay_clock( -1 )
{ {}
}
/* Try to send roughly two frames per RTT, bounded by limits on frame rate */ /* Try to send roughly two frames per RTT, bounded by limits on frame rate */
template<class MyState> template<class MyState>
@@ -103,16 +91,13 @@ void TransportSender<MyState>::calculate_timers( void )
mindelay_clock = now; mindelay_clock = now;
} }
next_send_time = std::max( mindelay_clock + SEND_MINDELAY, next_send_time = std::max( mindelay_clock + SEND_MINDELAY, sent_states.back().timestamp + send_interval() );
sent_states.back().timestamp + send_interval() ); } else if ( !( current_state == assumed_receiver_state->state ) && ( last_heard + ACTIVE_RETRY_TIMEOUT > now ) ) {
} else if ( !(current_state == assumed_receiver_state->state)
&& (last_heard + ACTIVE_RETRY_TIMEOUT > now) ) {
next_send_time = sent_states.back().timestamp + send_interval(); next_send_time = sent_states.back().timestamp + send_interval();
if ( mindelay_clock != uint64_t( -1 ) ) { if ( mindelay_clock != uint64_t( -1 ) ) {
next_send_time = std::max( next_send_time, mindelay_clock + SEND_MINDELAY ); next_send_time = std::max( next_send_time, mindelay_clock + SEND_MINDELAY );
} }
} else if ( !(current_state == sent_states.front().state ) } else if ( !( current_state == sent_states.front().state ) && ( last_heard + ACTIVE_RETRY_TIMEOUT > now ) ) {
&& (last_heard + ACTIVE_RETRY_TIMEOUT > now) ) {
next_send_time = sent_states.back().timestamp + connection->timeout() + ACK_DELAY; next_send_time = sent_states.back().timestamp + connection->timeout() + ACK_DELAY;
} else { } else {
next_send_time = uint64_t( -1 ); next_send_time = uint64_t( -1 );
@@ -160,8 +145,7 @@ void TransportSender<MyState>::tick( void )
uint64_t now = timestamp(); uint64_t now = timestamp();
if ( (now < next_ack_time) if ( ( now < next_ack_time ) && ( now < next_send_time ) ) {
&& (now < next_send_time) ) {
return; return;
} }
@@ -230,7 +214,9 @@ void TransportSender<MyState>::add_sent_state( uint64_t the_timestamp, uint64_t
sent_states.push_back( TimestampedState<MyState>( the_timestamp, num, state ) ); sent_states.push_back( TimestampedState<MyState>( the_timestamp, num, state ) );
if ( sent_states.size() > 32 ) { /* limit on state queue */ if ( sent_states.size() > 32 ) { /* limit on state queue */
typename sent_states_type::iterator last = sent_states.end(); 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 */ sent_states.erase( last ); /* erase state from middle of queue */
} }
} }
@@ -333,22 +319,27 @@ void TransportSender<MyState>::send_in_fragments( const std::string & diff, uint
shutdown_tries++; shutdown_tries++;
} }
std::vector<Fragment> fragments = fragmenter.make_fragments( inst, connection->get_MTU() std::vector<Fragment> fragments = fragmenter.make_fragments(
- Network::Connection::ADDED_BYTES inst, connection->get_MTU() - Network::Connection::ADDED_BYTES - Crypto::Session::ADDED_BYTES );
- Crypto::Session::ADDED_BYTES ); for ( std::vector<Fragment>::iterator i = fragments.begin(); i != fragments.end(); i++ ) {
for ( std::vector<Fragment>::iterator i = fragments.begin();
i != fragments.end();
i++ ) {
connection->send( i->tostring() ); connection->send( i->tostring() );
if ( verbose ) { 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", fprintf(
(unsigned int)(timestamp() % 100000), (int)inst.old_num(), (int)inst.new_num(), (int)i->id, (int)i->fragment_num, stderr,
(int)inst.ack_num(), (int)inst.throwaway_num(), (int)i->contents.size(), "[%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(), 1000.0 / (double)send_interval(),
(int)connection->timeout(), connection->get_SRTT() ); (int)connection->timeout(),
connection->get_SRTT() );
} }
} }
pending_data_ack = false; pending_data_ack = false;
@@ -417,8 +408,7 @@ void TransportSender<MyState>::attempt_prospective_resend_optimization( std::str
less than 1000 bytes. */ less than 1000 bytes. */
if ( ( resend_diff.size() <= proposed_diff.size() ) if ( ( resend_diff.size() <= proposed_diff.size() )
|| ( (resend_diff.size() < 1000) || ( ( resend_diff.size() < 1000 ) && ( resend_diff.size() - proposed_diff.size() < 100 ) ) ) {
&& (resend_diff.size() - proposed_diff.size() < 100) ) ) {
assumed_receiver_state = sent_states.begin(); assumed_receiver_state = sent_states.begin();
proposed_diff = resend_diff; proposed_diff = resend_diff;
} }
+15 -6
View File
@@ -30,18 +30,17 @@
also delete it here. also delete it here.
*/ */
#ifndef TRANSPORT_SENDER_HPP #ifndef TRANSPORT_SENDER_HPP
#define TRANSPORT_SENDER_HPP #define TRANSPORT_SENDER_HPP
#include <string>
#include <list> #include <list>
#include <string>
#include "src/crypto/prng.h"
#include "src/network/network.h" #include "src/network/network.h"
#include "src/protobufs/transportinstruction.pb.h" #include "src/protobufs/transportinstruction.pb.h"
#include "transportstate.h"
#include "transportfragment.h" #include "transportfragment.h"
#include "src/crypto/prng.h" #include "transportstate.h"
namespace Network { namespace Network {
using namespace TransportBuffers; using namespace TransportBuffers;
@@ -131,11 +130,21 @@ namespace Network {
void remote_heard( uint64_t ts ) { last_heard = ts; } void remote_heard( uint64_t ts ) { last_heard = ts; }
/* Starts shutdown sequence */ /* 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 */ /* Misc. getters and setters */
/* Cannot modify current_state while shutdown in progress */ /* Cannot modify current_state while shutdown in progress */
MyState &get_current_state( void ) { assert( !shutdown_in_progress ); return current_state; } MyState& get_current_state( void )
{
assert( !shutdown_in_progress );
return current_state;
}
void set_current_state( const MyState& x ) void set_current_state( const MyState& x )
{ {
assert( !shutdown_in_progress ); assert( !shutdown_in_progress );
+9 -11
View File
@@ -48,9 +48,7 @@ string Complete::act( const string &str )
parser.input( str[i], actions ); parser.input( str[i], actions );
/* apply actions to terminal and delete them */ /* apply actions to terminal and delete them */
for ( Actions::iterator it = actions.begin(); for ( Actions::iterator it = actions.begin(); it != actions.end(); it++ ) {
it != actions.end();
it++ ) {
Action& act = **it; Action& act = **it;
act.act_on_terminal( &terminal ); act.act_on_terminal( &terminal );
} }
@@ -131,16 +129,13 @@ bool Complete::set_echo_ack( uint64_t now )
bool ret = false; bool ret = false;
uint64_t newest_echo_ack = 0; uint64_t newest_echo_ack = 0;
for ( input_history_type::const_iterator i = input_history.begin(); for ( input_history_type::const_iterator i = input_history.begin(); i != input_history.end(); i++ ) {
i != input_history.end();
i++ ) {
if ( i->second <= now - ECHO_TIMEOUT ) { if ( i->second <= now - ECHO_TIMEOUT ) {
newest_echo_ack = i->first; newest_echo_ack = i->first;
} }
} }
for ( input_history_type::iterator i = input_history.begin(); for ( input_history_type::iterator i = input_history.begin(); i != input_history.end(); ) {
i != input_history.end(); ) {
input_history_type::iterator i_next = i; input_history_type::iterator i_next = i;
i_next++; i_next++;
if ( i->first < newest_echo_ack ) { if ( i->first < newest_echo_ack ) {
@@ -205,9 +200,12 @@ bool Complete::compare( const Complete &other ) const
if ( ( fb.ds.get_cursor_row() != other_fb.ds.get_cursor_row() ) if ( ( fb.ds.get_cursor_row() != other_fb.ds.get_cursor_row() )
|| ( fb.ds.get_cursor_col() != other_fb.ds.get_cursor_col() ) ) { || ( fb.ds.get_cursor_col() != other_fb.ds.get_cursor_col() ) ) {
fprintf( stderr, "Cursor mismatch: (%d, %d) vs. (%d, %d).\n", fprintf( stderr,
fb.ds.get_cursor_row(), fb.ds.get_cursor_col(), "Cursor mismatch: (%d, %d) vs. (%d, %d).\n",
other_fb.ds.get_cursor_row(), other_fb.ds.get_cursor_col() ); fb.ds.get_cursor_row(),
fb.ds.get_cursor_col(),
other_fb.ds.get_cursor_row(),
other_fb.ds.get_cursor_col() );
ret = true; ret = true;
} }
/* XXX should compare other terminal state too (mouse mode, bell. etc.) */ /* XXX should compare other terminal state too (mouse mode, bell. etc.) */
+5 -3
View File
@@ -42,7 +42,8 @@
/* This class represents the complete terminal -- a UTF8Parser feeding Actions to an Emulator. */ /* This class represents the complete terminal -- a UTF8Parser feeding Actions to an Emulator. */
namespace Terminal { namespace Terminal {
class Complete { class Complete
{
private: private:
Parser::UTF8Parser parser; Parser::UTF8Parser parser;
Terminal::Emulator terminal; Terminal::Emulator terminal;
@@ -60,8 +61,9 @@ namespace Terminal {
static const int ECHO_TIMEOUT = 50; /* for late ack */ static const int ECHO_TIMEOUT = 50; /* for late ack */
public: public:
Complete( size_t width, size_t height ) : parser(), terminal( width, height ), display( false ), Complete( size_t width, size_t height )
actions(), input_history(), echo_ack( 0 ) {} : parser(), terminal( width, height ), display( false ), actions(), input_history(), echo_ack( 0 )
{}
std::string act( const std::string& str ); std::string act( const std::string& str );
std::string act( const Parser::Action& act ); std::string act( const Parser::Action& act );
+11 -16
View File
@@ -33,9 +33,9 @@
#include <cassert> #include <cassert>
#include <typeinfo> #include <typeinfo>
#include "src/protobufs/userinput.pb.h"
#include "src/statesync/user.h" #include "src/statesync/user.h"
#include "src/util/fatal_assert.h" #include "src/util/fatal_assert.h"
#include "src/protobufs/userinput.pb.h"
using namespace Parser; using namespace Parser;
using namespace Network; using namespace Network;
@@ -48,9 +48,7 @@ void UserStream::subtract( const UserStream *prefix )
actions.clear(); actions.clear();
return; return;
} }
for ( std::deque<UserEvent>::const_iterator i = prefix->actions.begin(); for ( std::deque<UserEvent>::const_iterator i = prefix->actions.begin(); i != prefix->actions.end(); i++ ) {
i != prefix->actions.end();
i++ ) {
assert( this != prefix ); assert( this != prefix );
assert( !actions.empty() ); assert( !actions.empty() );
assert( *i == actions.front() ); assert( *i == actions.front() );
@@ -62,9 +60,7 @@ std::string UserStream::diff_from( const UserStream &existing ) const
{ {
std::deque<UserEvent>::const_iterator my_it = actions.begin(); std::deque<UserEvent>::const_iterator my_it = actions.begin();
for ( std::deque<UserEvent>::const_iterator i = existing.actions.begin(); for ( std::deque<UserEvent>::const_iterator i = existing.actions.begin(); i != existing.actions.end(); i++ ) {
i != existing.actions.end();
i++ ) {
assert( my_it != actions.end() ); assert( my_it != actions.end() );
assert( *i == *my_it ); assert( *i == *my_it );
my_it++; my_it++;
@@ -74,26 +70,25 @@ std::string UserStream::diff_from( const UserStream &existing ) const
while ( my_it != actions.end() ) { while ( my_it != actions.end() ) {
switch ( my_it->type ) { switch ( my_it->type ) {
case UserByteType: case UserByteType: {
{
char the_byte = my_it->userbyte.c; char the_byte = my_it->userbyte.c;
/* can we combine this with a previous Keystroke? */ /* can we combine this with a previous Keystroke? */
if ( ( output.instruction_size() > 0 ) if ( ( output.instruction_size() > 0 )
&& ( output.instruction( output.instruction_size() - 1 ).HasExtension( keystroke ) ) ) { && ( 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 ) ); output.mutable_instruction( output.instruction_size() - 1 )
->MutableExtension( keystroke )
->mutable_keys()
->append( std::string( &the_byte, 1 ) );
} else { } else {
Instruction* new_inst = output.add_instruction(); Instruction* new_inst = output.add_instruction();
new_inst->MutableExtension( keystroke )->set_keys( &the_byte, 1 ); new_inst->MutableExtension( keystroke )->set_keys( &the_byte, 1 );
} }
} } break;
break; case ResizeType: {
case ResizeType:
{
Instruction* new_inst = output.add_instruction(); Instruction* new_inst = output.add_instruction();
new_inst->MutableExtension( resize )->set_width( my_it->resize.width ); new_inst->MutableExtension( resize )->set_width( my_it->resize.width );
new_inst->MutableExtension( resize )->set_height( my_it->resize.height ); new_inst->MutableExtension( resize )->set_height( my_it->resize.height );
} } break;
break;
default: default:
assert( !"unexpected event type" ); assert( !"unexpected event type" );
break; break;
+8 -3
View File
@@ -41,7 +41,8 @@
#include "src/terminal/parseraction.h" #include "src/terminal/parseraction.h"
namespace Network { namespace Network {
enum UserEventType { enum UserEventType
{
UserByteType = 0, UserByteType = 0,
ResizeType = 1 ResizeType = 1
}; };
@@ -53,14 +54,18 @@ namespace Network {
Parser::UserByte userbyte; Parser::UserByte userbyte;
Parser::Resize resize; Parser::Resize resize;
UserEvent( const Parser::UserByte & s_userbyte ) : type( UserByteType ), userbyte( s_userbyte ), resize( -1, -1 ) {} 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::Resize& s_resize ) : type( ResizeType ), userbyte( 0 ), resize( s_resize ) {}
private: private:
UserEvent(); UserEvent();
public: public:
bool operator==( const UserEvent &x ) const { return ( type == x.type ) && ( userbyte == x.userbyte ) && ( resize == x.resize ); } bool operator==( const UserEvent& x ) const
{
return ( type == x.type ) && ( userbyte == x.userbyte ) && ( resize == x.resize );
}
}; };
class UserStream class UserStream
+3 -7
View File
@@ -40,8 +40,7 @@
const Parser::StateFamily Parser::family; const Parser::StateFamily Parser::family;
static void append_or_delete( Parser::ActionPointer act, static void append_or_delete( Parser::ActionPointer act, Parser::Actions& vec )
Parser::Actions &vec )
{ {
assert( act ); assert( act );
@@ -66,8 +65,7 @@ void Parser::Parser::input( wchar_t ch, Actions &ret )
} }
} }
Parser::UTF8Parser::UTF8Parser() Parser::UTF8Parser::UTF8Parser() : parser(), buf_len( 0 )
: parser(), buf_len( 0 )
{ {
assert( BUF_SIZE >= (size_t)MB_CUR_MAX ); assert( BUF_SIZE >= (size_t)MB_CUR_MAX );
buf[0] = '\0'; buf[0] = '\0';
@@ -155,9 +153,7 @@ void Parser::UTF8Parser::input( char c, Actions &ret )
} }
} }
Parser::Parser::Parser( const Parser &other ) Parser::Parser::Parser( const Parser& other ) : state( other.state ) {}
: state( other.state )
{}
Parser::Parser& Parser::Parser::operator=( const Parser& other ) Parser::Parser& Parser::Parser::operator=( const Parser& other )
{ {
+7 -9
View File
@@ -39,15 +39,16 @@
#include <cstring> #include <cstring>
#include <cwchar> #include <cwchar>
#include "parsertransition.h"
#include "src/terminal/parseraction.h"
#include "parserstate.h" #include "parserstate.h"
#include "parserstatefamily.h" #include "parserstatefamily.h"
#include "parsertransition.h"
#include "src/terminal/parseraction.h"
namespace Parser { namespace Parser {
extern const StateFamily family; extern const StateFamily family;
class Parser { class Parser
{
private: private:
State const* state; State const* state;
@@ -60,16 +61,13 @@ namespace Parser {
void input( wchar_t ch, Actions& actions ); void input( wchar_t ch, Actions& actions );
void reset_input( void ) void reset_input( void ) { state = &family.s_Ground; }
{
state = &family.s_Ground;
}
}; };
static const size_t BUF_SIZE = 8; static const size_t BUF_SIZE = 8;
class UTF8Parser { class UTF8Parser
{
private: private:
Parser parser; Parser parser;
+1 -2
View File
@@ -90,8 +90,7 @@ void OSC_End::act_on_terminal( Terminal::Emulator *emu ) const
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->dispatch.terminal_to_host.append( emu->user.input( this, emu->fb.ds.application_mode_cursor_keys ) );
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
+41 -31
View File
@@ -61,72 +61,90 @@ namespace Parser {
using ActionPointer = std::shared_ptr<Action>; using ActionPointer = std::shared_ptr<Action>;
using Actions = std::vector<ActionPointer>; using Actions = std::vector<ActionPointer>;
class Ignore : public Action { class Ignore : public Action
{
public: public:
std::string name( void ) { return std::string( "Ignore" ); } std::string name( void ) { return std::string( "Ignore" ); }
bool ignore() const { return true; } bool ignore() const { return true; }
}; };
class Print : public Action { class Print : public Action
{
public: public:
std::string name( void ) { return std::string( "Print" ); } std::string name( void ) { return std::string( "Print" ); }
void act_on_terminal( Terminal::Emulator* emu ) const; void act_on_terminal( Terminal::Emulator* emu ) const;
}; };
class Execute : public Action { class Execute : public Action
{
public: public:
std::string name( void ) { return std::string( "Execute" ); } std::string name( void ) { return std::string( "Execute" ); }
void act_on_terminal( Terminal::Emulator* emu ) const; void act_on_terminal( Terminal::Emulator* emu ) const;
}; };
class Clear : public Action { class Clear : public Action
{
public: public:
std::string name( void ) { return std::string( "Clear" ); } std::string name( void ) { return std::string( "Clear" ); }
void act_on_terminal( Terminal::Emulator* emu ) const; void act_on_terminal( Terminal::Emulator* emu ) const;
}; };
class Collect : public Action { class Collect : public Action
{
public: public:
std::string name( void ) { return std::string( "Collect" ); } std::string name( void ) { return std::string( "Collect" ); }
void act_on_terminal( Terminal::Emulator* emu ) const; void act_on_terminal( Terminal::Emulator* emu ) const;
}; };
class Param : public Action { class Param : public Action
{
public: public:
std::string name( void ) { return std::string( "Param" ); } std::string name( void ) { return std::string( "Param" ); }
void act_on_terminal( Terminal::Emulator* emu ) const; void act_on_terminal( Terminal::Emulator* emu ) const;
}; };
class Esc_Dispatch : public Action { class Esc_Dispatch : public Action
{
public: public:
std::string name( void ) { return std::string( "Esc_Dispatch" ); } std::string name( void ) { return std::string( "Esc_Dispatch" ); }
void act_on_terminal( Terminal::Emulator* emu ) const; void act_on_terminal( Terminal::Emulator* emu ) const;
}; };
class CSI_Dispatch : public Action { class CSI_Dispatch : public Action
{
public: public:
std::string name( void ) { return std::string( "CSI_Dispatch" ); } std::string name( void ) { return std::string( "CSI_Dispatch" ); }
void act_on_terminal( Terminal::Emulator* emu ) const; void act_on_terminal( Terminal::Emulator* emu ) const;
}; };
class Hook : public Action { class Hook : public Action
public: std::string name( void ) { return std::string( "Hook" ); } {
public:
std::string name( void ) { return std::string( "Hook" ); }
}; };
class Put : public Action { class Put : public Action
public: std::string name( void ) { return std::string( "Put" ); } {
public:
std::string name( void ) { return std::string( "Put" ); }
}; };
class Unhook : public Action { class Unhook : public Action
public: std::string name( void ) { return std::string( "Unhook" ); } {
public:
std::string name( void ) { return std::string( "Unhook" ); }
}; };
class OSC_Start : public Action { class OSC_Start : public Action
{
public: public:
std::string name( void ) { return std::string( "OSC_Start" ); } std::string name( void ) { return std::string( "OSC_Start" ); }
void act_on_terminal( Terminal::Emulator* emu ) const; void act_on_terminal( Terminal::Emulator* emu ) const;
}; };
class OSC_Put : public Action { class OSC_Put : public Action
{
public: public:
std::string name( void ) { return std::string( "OSC_Put" ); } std::string name( void ) { return std::string( "OSC_Put" ); }
void act_on_terminal( Terminal::Emulator* emu ) const; void act_on_terminal( Terminal::Emulator* emu ) const;
}; };
class OSC_End : public Action { class OSC_End : public Action
{
public: public:
std::string name( void ) { return std::string( "OSC_End" ); } 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*/ /* 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 */ char c; /* The user-source byte. We don't try to interpret the charset */
@@ -136,13 +154,11 @@ namespace Parser {
UserByte( int s_c ) : c( s_c ) {} UserByte( int s_c ) : c( s_c ) {}
bool operator==( const UserByte &other ) const bool operator==( const UserByte& other ) const { return c == other.c; }
{
return c == other.c;
}
}; };
class Resize : public Action { class Resize : public Action
{
/* resize event -- not part of the host-source state machine*/ /* resize event -- not part of the host-source state machine*/
public: public:
size_t width, height; size_t width, height;
@@ -150,15 +166,9 @@ namespace Parser {
std::string name( void ) { return std::string( "Resize" ); } 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 ) Resize( size_t s_width, size_t s_height ) : width( s_width ), height( s_height ) {}
: width( s_width ),
height( s_height )
{}
bool operator==( const Resize &other ) const bool operator==( const Resize& other ) const { return ( width == other.width ) && ( height == other.height ); }
{
return ( width == other.width ) && ( height == other.height );
}
}; };
} }
+6 -15
View File
@@ -39,10 +39,8 @@ using namespace Parser;
Transition State::anywhere_rule( wchar_t ch ) const Transition State::anywhere_rule( wchar_t ch ) const
{ {
if ( (ch == 0x18) || (ch == 0x1A) if ( ( ch == 0x18 ) || ( ch == 0x1A ) || ( ( 0x80 <= ch ) && ( ch <= 0x8F ) )
|| ((0x80 <= ch) && (ch <= 0x8F)) || ( ( 0x91 <= ch ) && ( ch <= 0x97 ) ) || ( ch == 0x99 ) || ( ch == 0x9A ) ) {
|| ((0x91 <= ch) && (ch <= 0x97))
|| (ch == 0x99) || (ch == 0x9A) ) {
return Transition( std::make_shared<Execute>(), &family->s_Ground ); return Transition( std::make_shared<Execute>(), &family->s_Ground );
} else if ( ch == 0x9C ) { } else if ( ch == 0x9C ) {
return Transition( &family->s_Ground ); return Transition( &family->s_Ground );
@@ -80,9 +78,7 @@ Transition State::input( wchar_t ch ) const
static bool C0_prime( wchar_t ch ) static bool C0_prime( wchar_t ch )
{ {
return (ch <= 0x17) return ( ch <= 0x17 ) || ( ch == 0x19 ) || ( ( 0x1C <= ch ) && ( ch <= 0x1F ) );
|| (ch == 0x19)
|| ( (0x1C <= ch) && (ch <= 0x1F) );
} }
static bool GLGR( wchar_t ch ) static bool GLGR( wchar_t ch )
@@ -119,12 +115,8 @@ Transition Escape::input_state_rule( wchar_t ch ) const
return Transition( std::make_shared<Collect>(), &family->s_Escape_Intermediate ); return Transition( std::make_shared<Collect>(), &family->s_Escape_Intermediate );
} }
if ( ( (0x30 <= ch) && (ch <= 0x4F) ) if ( ( ( 0x30 <= ch ) && ( ch <= 0x4F ) ) || ( ( 0x51 <= ch ) && ( ch <= 0x57 ) ) || ( ch == 0x59 )
|| ( (0x51 <= ch) && (ch <= 0x57) ) || ( ch == 0x5A ) || ( ch == 0x5C ) || ( ( 0x60 <= ch ) && ( ch <= 0x7E ) ) ) {
|| ( ch == 0x59 )
|| ( ch == 0x5A )
|| ( ch == 0x5C )
|| ( (0x60 <= ch) && (ch <= 0x7E) ) ) {
return Transition( std::make_shared<Esc_Dispatch>(), &family->s_Ground ); return Transition( std::make_shared<Esc_Dispatch>(), &family->s_Ground );
} }
@@ -179,8 +171,7 @@ Transition CSI_Entry::input_state_rule( wchar_t ch ) const
return Transition( std::make_shared<CSI_Dispatch>(), &family->s_Ground ); return Transition( std::make_shared<CSI_Dispatch>(), &family->s_Ground );
} }
if ( ( (0x30 <= ch) && (ch <= 0x39) ) if ( ( ( 0x30 <= ch ) && ( ch <= 0x39 ) ) || ( ch == 0x3B ) ) {
|| ( ch == 0x3B ) ) {
return Transition( std::make_shared<Param>(), &family->s_CSI_Param ); return Transition( std::make_shared<Param>(), &family->s_CSI_Param );
} }
+28 -14
View File
@@ -60,58 +60,72 @@ namespace Parser {
State& operator=( const State& ); State& operator=( const State& );
}; };
class Ground : public State { class Ground : public State
{
Transition input_state_rule( wchar_t ch ) const; Transition input_state_rule( wchar_t ch ) const;
}; };
class Escape : public State { class Escape : public State
{
ActionPointer enter( void ) const; ActionPointer enter( void ) const;
Transition input_state_rule( wchar_t ch ) 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; Transition input_state_rule( wchar_t ch ) const;
}; };
class CSI_Entry : public State { class CSI_Entry : public State
{
ActionPointer enter( void ) const; ActionPointer enter( void ) const;
Transition input_state_rule( wchar_t ch ) 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; 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; 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; Transition input_state_rule( wchar_t ch ) const;
}; };
class DCS_Entry : public State { class DCS_Entry : public State
{
ActionPointer enter( void ) const; ActionPointer enter( void ) const;
Transition input_state_rule( wchar_t ch ) 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; 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; Transition input_state_rule( wchar_t ch ) const;
}; };
class DCS_Passthrough : public State { class DCS_Passthrough : public State
{
ActionPointer enter( void ) const; ActionPointer enter( void ) const;
Transition input_state_rule( wchar_t ch ) const; Transition input_state_rule( wchar_t ch ) const;
ActionPointer exit( void ) const; ActionPointer exit( void ) const;
}; };
class DCS_Ignore : public State { class DCS_Ignore : public State
{
Transition input_state_rule( wchar_t ch ) const; Transition input_state_rule( wchar_t ch ) const;
}; };
class OSC_String : public State { class OSC_String : public State
{
ActionPointer enter( void ) const; ActionPointer enter( void ) const;
Transition input_state_rule( wchar_t ch ) const; Transition input_state_rule( wchar_t ch ) const;
ActionPointer exit( void ) 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; Transition input_state_rule( wchar_t ch ) const;
}; };
} }
+2 -4
View File
@@ -59,10 +59,8 @@ namespace Parser {
SOS_PM_APC_String s_SOS_PM_APC_String; SOS_PM_APC_String s_SOS_PM_APC_String;
StateFamily() StateFamily()
: s_Ground(), s_Escape(), s_Escape_Intermediate(), : s_Ground(), s_Escape(), s_Escape_Intermediate(), s_CSI_Entry(), s_CSI_Param(), s_CSI_Intermediate(),
s_CSI_Entry(), s_CSI_Param(), s_CSI_Intermediate(), s_CSI_Ignore(), s_CSI_Ignore(), s_DCS_Entry(), s_DCS_Param(), s_DCS_Intermediate(), s_DCS_Passthrough(), s_DCS_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_OSC_String(), s_SOS_PM_APC_String()
{ {
s_Ground.setfamily( this ); s_Ground.setfamily( this );
+1 -3
View File
@@ -48,9 +48,7 @@ namespace Parser {
ActionPointer action; ActionPointer action;
State* next_state; State* next_state;
Transition( const Transition &x ) Transition( const Transition& x ) : action( x.action ), next_state( x.next_state ) {}
: action( x.action ),
next_state( x.next_state ) {}
Transition& operator=( const Transition& t ) Transition& operator=( const Transition& t )
{ {
action = t.action; action = t.action;
+5 -12
View File
@@ -41,9 +41,7 @@
using namespace Terminal; using namespace Terminal;
Emulator::Emulator( size_t s_width, size_t s_height ) Emulator::Emulator( size_t s_width, size_t s_height ) : fb( s_width, s_height ), dispatch(), user() {}
: fb( s_width, s_height ), dispatch(), user()
{}
std::string Emulator::read_octets_to_host( void ) std::string Emulator::read_octets_to_host( void )
{ {
@@ -79,8 +77,7 @@ void Emulator::print( const Parser::Print *act )
fb.ds.move_col( 0 ); fb.ds.move_col( 0 );
fb.move_rows_autoscroll( 1 ); fb.move_rows_autoscroll( 1 );
this_cell = NULL; this_cell = NULL;
} else if ( fb.ds.auto_wrap_mode } else if ( fb.ds.auto_wrap_mode && ( chwidth == 2 )
&& (chwidth == 2)
&& ( fb.ds.get_cursor_col() == fb.ds.get_width() - 1 ) ) { && ( fb.ds.get_cursor_col() == fb.ds.get_width() - 1 ) ) {
/* wrap 2-cell chars if no room, even without will-wrap flag */ /* wrap 2-cell chars if no room, even without will-wrap flag */
fb.reset_cell( this_cell ); fb.reset_cell( this_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 */ this_cell->set_wide( chwidth == 2 ); /* chwidth had better be 1 or 2 here */
fb.apply_renditions_to_cell( this_cell ); fb.apply_renditions_to_cell( this_cell );
if ( chwidth == 2 if ( chwidth == 2 && fb.ds.get_cursor_col() + 1 < fb.ds.get_width() ) { /* erase overlapped cell */
&& 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 ) ); fb.reset_cell( fb.get_mutable_cell( fb.ds.get_cursor_row(), fb.ds.get_cursor_col() + 1 ) );
} }
@@ -138,8 +134,7 @@ void Emulator::print( const Parser::Print *act )
if ( !combining_cell->full() ) { if ( !combining_cell->full() ) {
combining_cell->append( ch ); combining_cell->append( ch );
} }
} } break;
break;
case -1: /* unprintable character */ case -1: /* unprintable character */
break; break;
default: default:
@@ -161,9 +156,7 @@ void Emulator::OSC_end( const Parser::OSC_End *act )
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 */ /* handle 7-bit ESC-encoding of C1 control characters */
if ( (dispatch.get_dispatch_chars().size() == 0) if ( ( dispatch.get_dispatch_chars().size() == 0 ) && ( 0x40 <= act->ch ) && ( act->ch <= 0x5F ) ) {
&& (0x40 <= act->ch)
&& (act->ch <= 0x5F) ) {
Parser::Esc_Dispatch act2 = *act; Parser::Esc_Dispatch act2 = *act;
act2.ch += 0x40; act2.ch += 0x40;
dispatch.dispatch( CONTROL, &act2, &fb ); dispatch.dispatch( CONTROL, &act2, &fb );
+3 -2
View File
@@ -41,11 +41,12 @@
#include "src/terminal/parseraction.h" #include "src/terminal/parseraction.h"
#include "src/terminal/terminalframebuffer.h" #include "src/terminal/terminalframebuffer.h"
#include "terminaldispatcher.h" #include "terminaldispatcher.h"
#include "terminaluserinput.h"
#include "terminaldisplay.h" #include "terminaldisplay.h"
#include "terminaluserinput.h"
namespace Terminal { namespace Terminal {
class Emulator { class Emulator
{
friend void Parser::Print::act_on_terminal( Emulator* ) const; friend void Parser::Print::act_on_terminal( Emulator* ) const;
friend void Parser::Execute::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::Clear::act_on_terminal( Emulator* ) const;
+19 -18
View File
@@ -36,17 +36,16 @@
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include "terminaldispatcher.h"
#include "src/terminal/parseraction.h" #include "src/terminal/parseraction.h"
#include "src/terminal/terminalframebuffer.h" #include "src/terminal/terminalframebuffer.h"
#include "terminaldispatcher.h"
using namespace Terminal; using namespace Terminal;
static const size_t MAXIMUM_CLIPBOARD_SIZE = 16 * 1024; static const size_t MAXIMUM_CLIPBOARD_SIZE = 16 * 1024;
Dispatcher::Dispatcher() Dispatcher::Dispatcher()
: params(), parsed_params(), parsed( false ), dispatch_chars(), : params(), parsed_params(), parsed( false ), dispatch_chars(), OSC_string(), terminal_to_host()
OSC_string(), terminal_to_host()
{} {}
void Dispatcher::newparamchar( const Parser::Param* act ) void Dispatcher::newparamchar( const Parser::Param* act )
@@ -142,7 +141,8 @@ int Dispatcher::getparam( size_t N, int defaultval )
ret = parsed_params[N]; ret = parsed_params[N];
} }
if ( ret < 1 ) ret = defaultval; if ( ret < 1 )
ret = defaultval;
return ret; return ret;
} }
@@ -159,8 +159,7 @@ int Dispatcher::param_count( void )
std::string Dispatcher::str( void ) std::string Dispatcher::str( void )
{ {
char assum[64]; char assum[64];
snprintf( assum, 64, "[dispatch=\"%s\" params=\"%s\"]", snprintf( assum, 64, "[dispatch=\"%s\" params=\"%s\"]", dispatch_chars.c_str(), params.c_str() );
dispatch_chars.c_str(), params.c_str() );
return std::string( assum ); return std::string( assum );
} }
@@ -171,9 +170,7 @@ DispatchRegistry & Terminal::get_global_dispatch_registry( void )
return global_dispatch_registry; return global_dispatch_registry;
} }
static void register_function( Function_Type type, static void register_function( Function_Type type, const std::string& dispatch_chars, Function f )
const std::string & dispatch_chars,
Function f )
{ {
switch ( type ) { switch ( type ) {
case ESCAPE: case ESCAPE:
@@ -188,7 +185,8 @@ static void register_function( Function_Type type,
} }
} }
Function::Function( Function_Type type, const std::string & dispatch_chars, Function::Function( Function_Type type,
const std::string& dispatch_chars,
void ( *s_function )( Framebuffer*, Dispatcher* ), void ( *s_function )( Framebuffer*, Dispatcher* ),
bool s_clears_wrap_state ) bool s_clears_wrap_state )
: function( s_function ), clears_wrap_state( s_clears_wrap_state ) : function( s_function ), clears_wrap_state( s_clears_wrap_state )
@@ -209,9 +207,15 @@ void Dispatcher::dispatch( Function_Type type, const Parser::Action *act, Frameb
dispatch_map_t* map = NULL; dispatch_map_t* map = NULL;
switch ( type ) { switch ( type ) {
case ESCAPE: map = &get_global_dispatch_registry().escape; break; case ESCAPE:
case CSI: map = &get_global_dispatch_registry().CSI; break; map = &get_global_dispatch_registry().escape;
case CONTROL: map = &get_global_dispatch_registry().control; break; break;
case CSI:
map = &get_global_dispatch_registry().CSI;
break;
case CONTROL:
map = &get_global_dispatch_registry().control;
break;
} }
std::string key = dispatch_chars; std::string key = dispatch_chars;
@@ -248,10 +252,7 @@ void Dispatcher::OSC_start( const Parser::OSC_Start *act __attribute((unused)) )
bool Dispatcher::operator==( const Dispatcher& x ) const bool Dispatcher::operator==( const Dispatcher& x ) const
{ {
return ( params == x.params ) return ( params == x.params ) && ( parsed_params == x.parsed_params ) && ( parsed == x.parsed )
&& ( parsed_params == x.parsed_params ) && ( dispatch_chars == x.dispatch_chars ) && ( OSC_string == x.OSC_string )
&& ( parsed == x.parsed )
&& ( dispatch_chars == x.dispatch_chars )
&& ( OSC_string == x.OSC_string )
&& ( terminal_to_host == x.terminal_to_host ); && ( terminal_to_host == x.terminal_to_host );
} }
+16 -7
View File
@@ -33,9 +33,9 @@
#ifndef TERMINALDISPATCHER_HPP #ifndef TERMINALDISPATCHER_HPP
#define TERMINALDISPATCHER_HPP #define TERMINALDISPATCHER_HPP
#include <vector>
#include <string>
#include <map> #include <map>
#include <string>
#include <vector>
namespace Parser { namespace Parser {
class Action; class Action;
@@ -54,12 +54,19 @@ namespace Terminal {
class Framebuffer; class Framebuffer;
class Dispatcher; class Dispatcher;
enum Function_Type { ESCAPE, CSI, CONTROL }; enum Function_Type
{
ESCAPE,
CSI,
CONTROL
};
class Function { class Function
{
public: public:
Function() : function( NULL ), clears_wrap_state( true ) {} Function() : function( NULL ), clears_wrap_state( true ) {}
Function( Function_Type type, const std::string & dispatch_chars, Function( Function_Type type,
const std::string& dispatch_chars,
void ( *s_function )( Framebuffer*, Dispatcher* ), void ( *s_function )( Framebuffer*, Dispatcher* ),
bool s_clears_wrap_state = true ); bool s_clears_wrap_state = true );
void ( *function )( Framebuffer*, Dispatcher* ); void ( *function )( Framebuffer*, Dispatcher* );
@@ -68,7 +75,8 @@ namespace Terminal {
using dispatch_map_t = std::map<std::string, Function>; using dispatch_map_t = std::map<std::string, Function>;
class DispatchRegistry { class DispatchRegistry
{
public: public:
dispatch_map_t escape; dispatch_map_t escape;
dispatch_map_t CSI; dispatch_map_t CSI;
@@ -79,7 +87,8 @@ namespace Terminal {
DispatchRegistry& get_global_dispatch_registry( void ); DispatchRegistry& get_global_dispatch_registry( void );
class Dispatcher { class Dispatcher
{
private: private:
std::string params; std::string params;
std::vector<int> parsed_params; std::vector<int> parsed_params;
+34 -55
View File
@@ -32,8 +32,8 @@
#include <cstdio> #include <cstdio>
#include "terminaldisplay.h"
#include "src/terminal/terminalframebuffer.h" #include "src/terminal/terminalframebuffer.h"
#include "terminaldisplay.h"
using namespace Terminal; using namespace Terminal;
@@ -54,8 +54,8 @@ std::string Display::close() const
{ {
return std::string( "\033[?1l\033[0m\033[?25h" return std::string( "\033[?1l\033[0m\033[?25h"
"\033[?1003l\033[?1002l\033[?1001l\033[?1000l" "\033[?1003l\033[?1002l\033[?1001l\033[?1000l"
"\033[?1015l\033[?1006l\033[?1005l" ) + "\033[?1015l\033[?1006l\033[?1005l" )
std::string( rmcup ? rmcup : "" ); + 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
@@ -71,18 +71,15 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
using title_type = Terminal::Framebuffer::title_type; using title_type = Terminal::Framebuffer::title_type;
/* has icon name or window title changed? */ /* has icon name or window title changed? */
if ( has_title && f.is_title_initialized() && if ( has_title && f.is_title_initialized()
( (!initialized) && ( ( !initialized ) || ( f.get_icon_name() != frame.last_frame.get_icon_name() )
|| (f.get_icon_name() != frame.last_frame.get_icon_name())
|| ( f.get_window_title() != frame.last_frame.get_window_title() ) ) ) { || ( f.get_window_title() != frame.last_frame.get_window_title() ) ) ) {
/* set icon name and window title */ /* set icon name and window title */
if ( f.get_icon_name() == f.get_window_title() ) { if ( f.get_icon_name() == f.get_window_title() ) {
/* write combined Icon Name and Window Title */ /* write combined Icon Name and Window Title */
frame.append( "\033]0;" ); frame.append( "\033]0;" );
const title_type& window_title( f.get_window_title() ); const title_type& window_title( f.get_window_title() );
for ( title_type::const_iterator i = window_title.begin(); for ( title_type::const_iterator i = window_title.begin(); i != window_title.end(); i++ ) {
i != window_title.end();
i++ ) {
frame.append( *i ); frame.append( *i );
} }
frame.append( '\007' ); frame.append( '\007' );
@@ -91,48 +88,39 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
/* write Icon Name */ /* write Icon Name */
frame.append( "\033]1;" ); frame.append( "\033]1;" );
const title_type& icon_name( f.get_icon_name() ); const title_type& icon_name( f.get_icon_name() );
for ( title_type::const_iterator i = icon_name.begin(); for ( title_type::const_iterator i = icon_name.begin(); i != icon_name.end(); i++ ) {
i != icon_name.end();
i++ ) {
frame.append( *i ); frame.append( *i );
} }
frame.append( '\007' ); frame.append( '\007' );
frame.append( "\033]2;" ); frame.append( "\033]2;" );
const title_type& window_title( f.get_window_title() ); const title_type& window_title( f.get_window_title() );
for ( title_type::const_iterator i = window_title.begin(); for ( title_type::const_iterator i = window_title.begin(); i != window_title.end(); i++ ) {
i != window_title.end();
i++ ) {
frame.append( *i ); frame.append( *i );
} }
frame.append( '\007' ); frame.append( '\007' );
} }
} }
/* has clipboard changed? */ /* 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;" ); frame.append( "\033]52;c;" );
const title_type& clipboard( f.get_clipboard() ); const title_type& clipboard( f.get_clipboard() );
for ( title_type::const_iterator i = clipboard.begin(); for ( title_type::const_iterator i = clipboard.begin(); i != clipboard.end(); i++ ) {
i != clipboard.end();
i++ ) {
frame.append( *i ); frame.append( *i );
} }
frame.append( '\007' ); frame.append( '\007' );
} }
/* has reverse video state changed? */ /* has reverse video state changed? */
if ( (!initialized) if ( ( !initialized ) || ( f.ds.reverse_video != frame.last_frame.ds.reverse_video ) ) {
|| (f.ds.reverse_video != frame.last_frame.ds.reverse_video) ) {
/* set 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 ); frame.append( tmp );
} }
/* has size changed? */ /* has size changed? */
if ( (!initialized) if ( ( !initialized ) || ( f.ds.get_width() != frame.last_frame.ds.get_width() )
|| (f.ds.get_width() != frame.last_frame.ds.get_width())
|| ( f.ds.get_height() != frame.last_frame.ds.get_height() ) ) { || ( f.ds.get_height() != frame.last_frame.ds.get_height() ) ) {
/* reset scrolling region */ /* reset scrolling region */
frame.append( "\033[r" ); frame.append( "\033[r" );
@@ -193,11 +181,8 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
scroll_height = 1; scroll_height = 1;
/* how big is the region that was scrolled? */ /* how big is the region that was scrolled? */
for ( int region_height = 1; for ( int region_height = 1; lines_scrolled + region_height < f.ds.get_height(); region_height++ ) {
lines_scrolled + region_height < f.ds.get_height(); if ( *f.get_row( region_height ) == *rows.at( lines_scrolled + region_height ) ) {
region_height++ ) {
if ( *f.get_row( region_height )
== *rows.at( lines_scrolled + region_height ) ) {
scroll_height = region_height + 1; scroll_height = region_height + 1;
} else { } else {
break; 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 /* Common case: if we're already on the bottom line and we're scrolling the whole
* screen, just do a CR and LFs. * screen, just do a CR and LFs.
*/ */
if ( scroll_height + lines_scrolled == f.ds.get_height() if ( scroll_height + lines_scrolled == f.ds.get_height() && frame.cursor_y + 1 == f.ds.get_height() ) {
&& frame.cursor_y + 1 == f.ds.get_height() ) {
frame.append( '\r' ); frame.append( '\r' );
frame.append( lines_scrolled, '\n' ); frame.append( lines_scrolled, '\n' );
frame.cursor_x = 0; frame.cursor_x = 0;
} else { } else {
/* set scrolling region */ /* set scrolling region */
snprintf( tmp, 64, "\033[%d;%dr", snprintf( tmp, 64, "\033[%d;%dr", top_margin + 1, bottom_margin + 1 );
top_margin + 1, bottom_margin + 1);
frame.append( tmp ); frame.append( tmp );
/* go to bottom of scrolling region */ /* 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? */ /* has cursor location changed? */
if ( (!initialized) if ( ( !initialized ) || ( f.ds.get_cursor_row() != frame.cursor_y )
|| (f.ds.get_cursor_row() != frame.cursor_y)
|| ( f.ds.get_cursor_col() != frame.cursor_x ) ) { || ( f.ds.get_cursor_col() != frame.cursor_x ) ) {
frame.append_move( f.ds.get_cursor_row(), f.ds.get_cursor_col() ); frame.append_move( f.ds.get_cursor_row(), f.ds.get_cursor_col() );
} }
/* has cursor visibility changed? */ /* has cursor visibility changed? */
if ( (!initialized) if ( ( !initialized ) || ( f.ds.cursor_visible != frame.cursor_visible ) ) {
|| (f.ds.cursor_visible != frame.cursor_visible) ) {
if ( f.ds.cursor_visible ) { if ( f.ds.cursor_visible ) {
frame.append( "\033[?25h" ); frame.append( "\033[?25h" );
} else { } else {
@@ -290,14 +271,12 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
frame.update_rendition( f.ds.get_renditions(), !initialized ); frame.update_rendition( f.ds.get_renditions(), !initialized );
/* has bracketed paste mode changed? */ /* has bracketed paste mode changed? */
if ( (!initialized) if ( ( !initialized ) || ( f.ds.bracketed_paste != frame.last_frame.ds.bracketed_paste ) ) {
|| (f.ds.bracketed_paste != frame.last_frame.ds.bracketed_paste) ) {
frame.append( f.ds.bracketed_paste ? "\033[?2004h" : "\033[?2004l" ); frame.append( f.ds.bracketed_paste ? "\033[?2004h" : "\033[?2004l" );
} }
/* has mouse reporting mode changed? */ /* has mouse reporting mode changed? */
if ( (!initialized) if ( ( !initialized ) || ( f.ds.mouse_reporting_mode != frame.last_frame.ds.mouse_reporting_mode ) ) {
|| (f.ds.mouse_reporting_mode != frame.last_frame.ds.mouse_reporting_mode) ) {
if ( f.ds.mouse_reporting_mode == DrawState::MOUSE_REPORTING_NONE ) { if ( f.ds.mouse_reporting_mode == DrawState::MOUSE_REPORTING_NONE ) {
frame.append( "\033[?1003l" ); frame.append( "\033[?1003l" );
frame.append( "\033[?1002l" ); frame.append( "\033[?1002l" );
@@ -314,14 +293,12 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
} }
/* has mouse focus mode changed? */ /* has mouse focus mode changed? */
if ( (!initialized) if ( ( !initialized ) || ( f.ds.mouse_focus_event != frame.last_frame.ds.mouse_focus_event ) ) {
|| (f.ds.mouse_focus_event != frame.last_frame.ds.mouse_focus_event) ) {
frame.append( f.ds.mouse_focus_event ? "\033[?1004h" : "\033[?1004l" ); frame.append( f.ds.mouse_focus_event ? "\033[?1004h" : "\033[?1004l" );
} }
/* has mouse encoding mode changed? */ /* has mouse encoding mode changed? */
if ( (!initialized) if ( ( !initialized ) || ( f.ds.mouse_encoding_mode != frame.last_frame.ds.mouse_encoding_mode ) ) {
|| (f.ds.mouse_encoding_mode != frame.last_frame.ds.mouse_encoding_mode) ) {
if ( f.ds.mouse_encoding_mode == DrawState::MOUSE_ENCODING_DEFAULT ) { if ( f.ds.mouse_encoding_mode == DrawState::MOUSE_ENCODING_DEFAULT ) {
frame.append( "\033[?1015l" ); frame.append( "\033[?1015l" );
frame.append( "\033[?1006l" ); frame.append( "\033[?1006l" );
@@ -339,7 +316,12 @@ std::string Display::new_frame( bool initialized, const Framebuffer &last, const
return frame.str; 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; int frame_x = 0;
@@ -374,9 +356,7 @@ bool Display::put_row( bool initialized, FrameState &frame, const Framebuffer &f
const Cell& cell = cells.at( frame_x ); const Cell& cell = cells.at( frame_x );
/* Does cell need to be drawn? Skip all this. */ /* Does cell need to be drawn? Skip all this. */
if ( initialized if ( initialized && !clear_count && ( cell == old_cells.at( frame_x ) ) ) {
&& !clear_count
&& ( cell == old_cells.at( frame_x ) ) ) {
frame_x += cell.get_width(); frame_x += cell.get_width();
continue; continue;
} }
@@ -418,7 +398,6 @@ bool Display::put_row( bool initialized, FrameState &frame, const Framebuffer &f
} }
} }
/* Now draw a character cell. */ /* Now draw a character cell. */
/* Move to the right position. */ /* Move to the right position. */
const int cell_width = cell.get_width(); 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 if ( !( wrote_last_cell && ( frame_y < f.ds.get_height() - 1 ) ) ) {
&& (frame_y < f.ds.get_height() - 1) ) ) {
return false; return false;
} }
/* To hint that a word-select should group the end of one line /* To hint that a word-select should group the end of one line
@@ -481,8 +459,7 @@ bool Display::put_row( bool initialized, FrameState &frame, const Framebuffer &f
} }
FrameState::FrameState( const Framebuffer& s_last ) FrameState::FrameState( const Framebuffer& s_last )
: str(), cursor_x(0), cursor_y(0), current_rendition( 0 ), : str(), cursor_x( 0 ), cursor_y( 0 ), current_rendition( 0 ), cursor_visible( s_last.ds.cursor_visible ),
cursor_visible( s_last.ds.cursor_visible ),
last_frame( s_last ) last_frame( s_last )
{ {
/* Preallocate for better performance. Make a guess-- doesn't matter for correctness */ /* 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 ) 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 */ /* turn off cursor if necessary before moving cursor */
if ( cursor_visible ) { if ( cursor_visible ) {
append( "\033[?25l" ); append( "\033[?25l" );
@@ -528,7 +506,8 @@ void FrameState::append_move( int y, int x )
append( tmp ); append( tmp );
} }
void FrameState::update_rendition(const Renditions &r, bool force) { void FrameState::update_rendition( const Renditions& r, bool force )
{
if ( force || !( current_rendition == r ) ) { if ( force || !( current_rendition == r ) ) {
/* print renditions */ /* print renditions */
append_string( r.sgr() ); append_string( r.sgr() );
+10 -3
View File
@@ -37,7 +37,8 @@
namespace Terminal { namespace Terminal {
/* variables used within a new_frame */ /* variables used within a new_frame */
class FrameState { class FrameState
{
public: public:
std::string str; std::string str;
@@ -61,7 +62,8 @@ namespace Terminal {
void update_rendition( const Renditions& r, bool force = false ); void update_rendition( const Renditions& r, bool force = false );
}; };
class Display { class Display
{
private: private:
bool has_ech; /* erase character is part of vt200 but not supported by tmux bool has_ech; /* erase character is part of vt200 but not supported by tmux
(or by "screen" terminfo entry, which is what tmux advertises) */ (or by "screen" terminfo entry, which is what tmux advertises) */
@@ -72,7 +74,12 @@ namespace Terminal {
const char *smcup, *rmcup; /* enter and exit alternate screen mode */ 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 open() const;
+5 -9
View File
@@ -36,8 +36,8 @@
#include "src/include/config.h" #include "src/include/config.h"
#include "terminaldisplay.h" #include "terminaldisplay.h"
#include <string>
#include <stdexcept> #include <stdexcept>
#include <string>
#if defined HAVE_NCURSESW_CURSES_H #if defined HAVE_NCURSESW_CURSES_H
#include <ncursesw/curses.h> #include <ncursesw/curses.h>
@@ -113,18 +113,14 @@ Display::Display( bool use_environment )
/* Check if we can set the window title and icon name. terminfo does not /* 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 have reliable information on this, so we hardcode a whitelist of
terminal type prefixes. */ terminal type prefixes. */
static const char * const title_term_types[] = { static const char* const title_term_types[]
"xterm", "rxvt", "kterm", "Eterm", "alacritty", "screen", "tmux" = { "xterm", "rxvt", "kterm", "Eterm", "alacritty", "screen", "tmux" };
};
has_title = false; has_title = false;
const char* term_type = getenv( "TERM" ); const char* term_type = getenv( "TERM" );
if ( term_type ) { if ( term_type ) {
for ( size_t i = 0; for ( size_t i = 0; i < sizeof( title_term_types ) / sizeof( const char* ); i++ ) {
i < sizeof( title_term_types ) / sizeof( const char * ); if ( 0 == strncmp( term_type, title_term_types[i], strlen( title_term_types[i] ) ) ) {
i++ ) {
if ( 0 == strncmp( term_type, title_term_types[ i ],
strlen( title_term_types[ i ] ) ) ) {
has_title = true; has_title = true;
break; break;
} }
+84 -72
View File
@@ -39,11 +39,7 @@
using namespace Terminal; using namespace Terminal;
Cell::Cell( color_type background_color ) Cell::Cell( color_type background_color )
: contents(), : contents(), renditions( background_color ), wide( false ), fallback( false ), wrap( false )
renditions( background_color ),
wide( false ),
fallback( false ),
wrap( false )
{} {}
void Cell::reset( color_type background_color ) void Cell::reset( color_type background_color )
@@ -64,21 +60,20 @@ void DrawState::reinitialize_tabs( unsigned int start )
} }
DrawState::DrawState( int s_width, int s_height ) DrawState::DrawState( int s_width, int s_height )
: width( s_width ), height( s_height ), : width( s_width ), height( s_height ), cursor_col( 0 ), cursor_row( 0 ), combining_char_col( 0 ),
cursor_col( 0 ), cursor_row( 0 ), combining_char_row( 0 ), default_tabs( true ), tabs( s_width ), scrolling_region_top_row( 0 ),
combining_char_col( 0 ), combining_char_row( 0 ), default_tabs( true ), tabs( s_width ), scrolling_region_bottom_row( height - 1 ), renditions( 0 ), save(), next_print_will_wrap( false ),
scrolling_region_top_row( 0 ), scrolling_region_bottom_row( height - 1 ), origin_mode( false ), auto_wrap_mode( true ), insert_mode( false ), cursor_visible( true ),
renditions( 0 ), save(), reverse_video( false ), bracketed_paste( false ), mouse_reporting_mode( MOUSE_REPORTING_NONE ),
next_print_will_wrap( false ), origin_mode( false ), auto_wrap_mode( true ), mouse_focus_event( false ), mouse_alternate_scroll( false ), mouse_encoding_mode( MOUSE_ENCODING_DEFAULT ),
insert_mode( false ), cursor_visible( true ), reverse_video( false ), application_mode_cursor_keys( 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 ); reinitialize_tabs( 0 );
} }
Framebuffer::Framebuffer( int s_width, int s_height ) 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_height > 0 );
assert( s_width > 0 ); assert( s_width > 0 );
@@ -89,10 +84,9 @@ Framebuffer::Framebuffer( int s_width, int s_height )
Framebuffer::Framebuffer( const Framebuffer& other ) Framebuffer::Framebuffer( const Framebuffer& other )
: rows( other.rows ), icon_name( other.icon_name ), window_title( other.window_title ), : rows( other.rows ), icon_name( other.icon_name ), window_title( other.window_title ),
clipboard( other.clipboard ), bell_count( other.bell_count ), clipboard( other.clipboard ), bell_count( other.bell_count ), title_initialized( other.title_initialized ),
title_initialized( other.title_initialized ), ds( other.ds ) ds( other.ds )
{ {}
}
Framebuffer& Framebuffer::operator=( const Framebuffer& other ) Framebuffer& Framebuffer::operator=( const Framebuffer& other )
{ {
@@ -125,10 +119,14 @@ void DrawState::new_grapheme( void )
void DrawState::snap_cursor_to_border( void ) void DrawState::snap_cursor_to_border( void )
{ {
if ( cursor_row < limit_top() ) cursor_row = limit_top(); if ( cursor_row < limit_top() )
if ( cursor_row > limit_bottom() ) cursor_row = limit_bottom(); cursor_row = limit_top();
if ( cursor_col < 0 ) cursor_col = 0; if ( cursor_row > limit_bottom() )
if ( cursor_col >= width ) cursor_col = width - 1; 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 ) void DrawState::move_row( int N, bool relative )
@@ -191,8 +189,7 @@ void Framebuffer::move_rows_autoscroll( int rows )
Cell* Framebuffer::get_combining_cell( void ) Cell* Framebuffer::get_combining_cell( void )
{ {
if ( (ds.get_combining_char_col() < 0) if ( ( ds.get_combining_char_col() < 0 ) || ( ds.get_combining_char_row() < 0 )
|| (ds.get_combining_char_row() < 0)
|| ( ds.get_combining_char_col() >= ds.get_width() ) || ( ds.get_combining_char_col() >= ds.get_width() )
|| ( ds.get_combining_char_row() >= ds.get_height() ) ) { || ( ds.get_combining_char_row() >= ds.get_height() ) ) {
return NULL; return NULL;
@@ -238,8 +235,10 @@ void DrawState::set_scrolling_region( int top, int bottom )
scrolling_region_top_row = top; scrolling_region_top_row = top;
scrolling_region_bottom_row = bottom; scrolling_region_bottom_row = bottom;
if ( scrolling_region_top_row < 0 ) scrolling_region_top_row = 0; if ( scrolling_region_top_row < 0 )
if ( scrolling_region_bottom_row >= height ) scrolling_region_bottom_row = height - 1; 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 ) if ( scrolling_region_bottom_row < scrolling_region_top_row )
scrolling_region_bottom_row = scrolling_region_top_row; scrolling_region_bottom_row = scrolling_region_top_row;
@@ -270,10 +269,7 @@ void Framebuffer::apply_renditions_to_cell( Cell *cell )
} }
SavedCursor::SavedCursor() SavedCursor::SavedCursor()
: cursor_col( 0 ), cursor_row( 0 ), : cursor_col( 0 ), cursor_row( 0 ), renditions( 0 ), auto_wrap_mode( true ), origin_mode( false )
renditions( 0 ),
auto_wrap_mode( true ),
origin_mode( false )
{} {}
void DrawState::save_cursor( void ) void DrawState::save_cursor( void )
@@ -323,8 +319,7 @@ void Framebuffer::insert_line( int before_row, int count )
void Framebuffer::delete_line( int row, int count ) void Framebuffer::delete_line( int row, int count )
{ {
if ( (row < ds.get_scrolling_region_top_row()) if ( ( row < ds.get_scrolling_region_top_row() ) || ( row > ds.get_scrolling_region_bottom_row() ) ) {
|| (row > ds.get_scrolling_region_bottom_row()) ) {
return; return;
} }
@@ -414,9 +409,7 @@ void Framebuffer::resize( int s_width, int s_height )
if ( oldwidth == s_width ) { if ( oldwidth == s_width ) {
return; return;
} }
for ( rows_type::iterator i = rows.begin(); for ( rows_type::iterator i = rows.begin(); i != rows.end() && *i != blankrow; i++ ) {
i != rows.end() && *i != blankrow;
i++ ) {
*i = std::make_shared<Row>( **i ); *i = std::make_shared<Row>( **i );
( *i )->set_wrap( false ); ( *i )->set_wrap( false );
( *i )->cells.resize( s_width, Cell( ds.get_background_rendition() ) ); ( *i )->cells.resize( s_width, Cell( ds.get_background_rendition() ) );
@@ -425,8 +418,7 @@ void Framebuffer::resize( int s_width, int s_height )
void DrawState::resize( int s_width, int s_height ) void DrawState::resize( int s_width, int s_height )
{ {
if ( (width != s_width) if ( ( width != s_width ) || ( height != s_height ) ) {
|| (height != s_height) ) {
/* reset entire scrolling region on any resize */ /* reset entire scrolling region on any resize */
/* xterm and rxvt-unicode do this. gnome-terminal only /* xterm and rxvt-unicode do this. gnome-terminal only
resets scrolling region if it has to become smaller in resize */ 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 */ /* saved cursor will be snapped to border on restore */
/* invalidate combining char cell if necessary */ /* invalidate combining char cell if necessary */
if ( (combining_char_col >= width) if ( ( combining_char_col >= width ) || ( combining_char_row >= height ) ) {
|| (combining_char_row >= height) ) {
combining_char_col = combining_char_row = -1; combining_char_col = combining_char_row = -1;
} }
} }
Renditions::Renditions( color_type s_background ) Renditions::Renditions( color_type s_background )
: foreground_color( 0 ), background_color( s_background ), : foreground_color( 0 ), background_color( s_background ), attributes( 0 )
attributes( 0 )
{} {}
/* This routine cannot be used to set a color beyond the 16-color set. */ /* This routine cannot be used to set a color beyond the 16-color set. */
@@ -491,13 +481,32 @@ void Renditions::set_rendition( color_type num )
bool value = num < 9; bool value = num < 9;
switch ( num ) { switch ( num ) {
case 1: case 22: set_attribute(bold, value); break; case 1:
case 3: case 23: set_attribute(italic, value); break; case 22:
case 4: case 24: set_attribute(underlined, value); break; set_attribute( bold, value );
case 5: case 25: set_attribute(blink, value); break; break;
case 7: case 27: set_attribute(inverse, value); break; case 3:
case 8: case 28: set_attribute(invisible, value); break; case 23:
default: break; /* ignore unknown rendition */ 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 */
} }
} }
@@ -525,12 +534,18 @@ std::string Renditions::sgr( void ) const
char col[64]; char col[64];
ret.append( "\033[0" ); ret.append( "\033[0" );
if ( get_attribute( bold ) ) ret.append( ";1" ); if ( get_attribute( bold ) )
if ( get_attribute( italic ) ) ret.append( ";3" ); ret.append( ";1" );
if ( get_attribute( underlined ) ) ret.append( ";4" ); if ( get_attribute( italic ) )
if ( get_attribute( blink ) ) ret.append( ";5" ); ret.append( ";3" );
if ( get_attribute( inverse ) ) ret.append( ";7" ); if ( get_attribute( underlined ) )
if ( get_attribute( invisible ) ) ret.append( ";8" ); 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 ) { if ( foreground_color ) {
// Since foreground_color is a 25-bit field, it is promoted to an int when // Since foreground_color is a 25-bit field, it is promoted to an int when
@@ -538,7 +553,9 @@ std::string Renditions::sgr( void ) const
// https://timsong-cpp.github.io/cppwp/n4659/conv.prom#5.) The correct // https://timsong-cpp.github.io/cppwp/n4659/conv.prom#5.) The correct
// printf format specifier is thus %d. // printf format specifier is thus %d.
if ( is_true_color( foreground_color ) ) { if ( is_true_color( foreground_color ) ) {
snprintf( col, sizeof( col ), ";38;2;%d;%d;%d", snprintf( col,
sizeof( col ),
";38;2;%d;%d;%d",
( foreground_color >> 16 ) & 0xff, ( foreground_color >> 16 ) & 0xff,
( foreground_color >> 8 ) & 0xff, ( foreground_color >> 8 ) & 0xff,
foreground_color & 0xff ); foreground_color & 0xff );
@@ -557,7 +574,9 @@ std::string Renditions::sgr( void ) const
if ( background_color ) { if ( background_color ) {
// See comment above about bit-field promotion; it applies here as well. // See comment above about bit-field promotion; it applies here as well.
if ( is_true_color( background_color ) ) { if ( is_true_color( background_color ) ) {
snprintf( col, sizeof( col ), ";48;2;%d;%d;%d", snprintf( col,
sizeof( col ),
";48;2;%d;%d;%d",
( background_color >> 16 ) & 0xff, ( background_color >> 16 ) & 0xff,
( background_color >> 8 ) & 0xff, ( background_color >> 8 ) & 0xff,
background_color & 0xff ); background_color & 0xff );
@@ -578,9 +597,7 @@ std::string Renditions::sgr( void ) const
void Row::reset( color_type background_color ) void Row::reset( color_type background_color )
{ {
gen = get_gen(); gen = get_gen();
for ( cells_type::iterator i = cells.begin(); for ( cells_type::iterator i = cells.begin(); i != cells.end(); i++ ) {
i != cells.end();
i++ ) {
i->reset( background_color ); i->reset( background_color );
} }
} }
@@ -604,9 +621,7 @@ std::string Cell::debug_contents( void ) const
chars.append( "' [" ); chars.append( "' [" );
const char* lazycomma = ""; const char* lazycomma = "";
char buf[64]; char buf[64];
for ( content_type::const_iterator i = contents.begin(); for ( content_type::const_iterator i = contents.begin(); i < contents.end(); i++ ) {
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 ); chars.append( buf );
@@ -627,13 +642,13 @@ bool Cell::compare( const Cell &other ) const
if ( grapheme != other_grapheme ) { if ( grapheme != other_grapheme ) {
ret = true; ret = true;
fprintf( stderr, "Graphemes: '%s' vs. '%s'\n", fprintf( stderr, "Graphemes: '%s' vs. '%s'\n", grapheme.c_str(), other_grapheme.c_str() );
grapheme.c_str(), other_grapheme.c_str() );
} }
if ( !contents_match( other ) ) { if ( !contents_match( other ) ) {
// ret = true; // ret = true;
fprintf( stderr, "Contents: %s (%ld) vs. %s (%ld)\n", fprintf( stderr,
"Contents: %s (%ld) vs. %s (%ld)\n",
debug_contents().c_str(), debug_contents().c_str(),
static_cast<long int>( contents.size() ), static_cast<long int>( contents.size() ),
other.debug_contents().c_str(), other.debug_contents().c_str(),
@@ -646,15 +661,13 @@ bool Cell::compare( const Cell &other ) const
// manipulated. (See [conv.prom] in various C++ standards, e.g., // manipulated. (See [conv.prom] in various C++ standards, e.g.,
// https://timsong-cpp.github.io/cppwp/n4659/conv.prom#5.) The correct // https://timsong-cpp.github.io/cppwp/n4659/conv.prom#5.) The correct
// printf format specifier is thus %d. // printf format specifier is thus %d.
fprintf( stderr, "fallback: %d vs. %d\n", fprintf( stderr, "fallback: %d vs. %d\n", fallback, other.fallback );
fallback, other.fallback );
} }
if ( wide != other.wide ) { if ( wide != other.wide ) {
ret = true; ret = true;
// See comment above about bit-field promotion; it applies here as well. // See comment above about bit-field promotion; it applies here as well.
fprintf( stderr, "width: %d vs. %d\n", fprintf( stderr, "width: %d vs. %d\n", wide, other.wide );
wide, other.wide );
} }
if ( !( renditions == other.renditions ) ) { if ( !( renditions == other.renditions ) ) {
@@ -665,8 +678,7 @@ bool Cell::compare( const Cell &other ) const
if ( wrap != other.wrap ) { if ( wrap != other.wrap ) {
ret = true; ret = true;
// See comment above about bit-field promotion; it applies here as well. // See comment above about bit-field promotion; it applies here as well.
fprintf( stderr, "wrap: %d vs. %d\n", fprintf( stderr, "wrap: %d vs. %d\n", wrap, other.wrap );
wrap, other.wrap );
} }
return ret; return ret;
+58 -44
View File
@@ -47,9 +47,20 @@
namespace Terminal { namespace Terminal {
using color_type = uint32_t; using color_type = uint32_t;
class Renditions { class Renditions
{
public: public:
typedef enum { bold, faint, italic, underlined, blink, inverse, invisible, SIZE } attribute_type; typedef enum
{
bold,
faint,
italic,
underlined,
blink,
inverse,
invisible,
SIZE
} attribute_type;
private: private:
static const uint64_t true_color_mask = 0x1000000; static const uint64_t true_color_mask = 0x1000000;
@@ -64,34 +75,31 @@ namespace Terminal {
void set_rendition( color_type num ); void set_rendition( color_type num );
std::string sgr( void ) const; std::string sgr( void ) const;
static unsigned int make_true_color( unsigned int r, unsigned int g, unsigned int 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; return true_color_mask | ( r << 16 ) | ( g << 8 ) | b;
} }
static bool is_true_color(unsigned int color) { static bool is_true_color( unsigned int color ) { return ( color & true_color_mask ) != 0; }
return (color & true_color_mask) != 0;
}
// unsigned int get_foreground_rendition() const { return foreground_color; } // unsigned int get_foreground_rendition() const { return foreground_color; }
unsigned int get_background_rendition() const { return background_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 ) return ( attributes == x.attributes ) && ( foreground_color == x.foreground_color )
&& ( foreground_color == x.foreground_color )
&& ( background_color == x.background_color ); && ( background_color == x.background_color );
} }
void set_attribute( attribute_type attr, bool val ) void set_attribute( attribute_type attr, bool val )
{ {
attributes = val ? attributes = val ? ( attributes | ( 1 << attr ) ) : ( attributes & ~( 1 << attr ) );
( attributes | (1 << attr) ) :
( attributes & ~(1 << attr) );
} }
bool get_attribute( attribute_type attr ) const { return attributes & ( 1 << attr ); } bool get_attribute( attribute_type attr ) const { return attributes & ( 1 << attr ); }
void clear_attributes() { attributes = 0; } void clear_attributes() { attributes = 0; }
}; };
class Cell { class Cell
{
private: private:
typedef std::string content_type; /* can be std::string, std::vector<uint8_t>, or __gnu_cxx::__vstring */ typedef std::string content_type; /* can be std::string, std::vector<uint8_t>, or __gnu_cxx::__vstring */
content_type contents; content_type contents;
@@ -102,6 +110,7 @@ namespace Terminal {
private: private:
Cell(); Cell();
public: public:
Cell( color_type background_color ); Cell( color_type background_color );
@@ -109,11 +118,8 @@ namespace Terminal {
bool operator==( const Cell& x ) const bool operator==( const Cell& x ) const
{ {
return ( (contents == x.contents) return ( ( contents == x.contents ) && ( fallback == x.fallback ) && ( wide == x.wide )
&& (fallback == x.fallback) && ( renditions == x.renditions ) && ( wrap == x.wrap ) );
&& (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 ); }
@@ -129,15 +135,12 @@ namespace Terminal {
bool is_blank( void ) const bool is_blank( void ) const
{ {
// XXX fix. // XXX fix.
return ( contents.empty() return ( contents.empty() || contents == " " || contents == "\xC2\xA0" );
|| contents == " "
|| contents == "\xC2\xA0" );
} }
bool contents_match( const Cell& other ) const bool contents_match( const Cell& other ) const
{ {
return ( is_blank() && other.is_blank() ) return ( is_blank() && other.is_blank() ) || ( contents == other.contents );
|| ( contents == other.contents );
} }
bool compare( const Cell& other ) const; bool compare( const Cell& other ) const;
@@ -207,7 +210,8 @@ namespace Terminal {
void set_wrap( bool f ) { wrap = f; } void set_wrap( bool f ) { wrap = f; }
}; };
class Row { class Row
{
public: public:
typedef std::vector<Cell> cells_type; typedef std::vector<Cell> cells_type;
cells_type cells; cells_type cells;
@@ -218,6 +222,7 @@ namespace Terminal {
private: private:
Row(); Row();
public: public:
Row( const size_t s_width, const color_type background_color ); Row( const size_t s_width, const color_type background_color );
@@ -226,10 +231,7 @@ namespace Terminal {
void reset( color_type background_color ); void reset( color_type background_color );
bool operator==( const Row &x ) const bool operator==( const Row& x ) const { return ( gen == x.gen && cells == x.cells ); }
{
return ( gen == x.gen && cells == x.cells );
}
bool get_wrap( void ) const { return cells.back().get_wrap(); } bool get_wrap( void ) const { return cells.back().get_wrap(); }
void set_wrap( bool w ) { cells.back().set_wrap( w ); } void set_wrap( bool w ) { cells.back().set_wrap( w ); }
@@ -237,7 +239,8 @@ namespace Terminal {
uint64_t get_gen() const; uint64_t get_gen() const;
}; };
class SavedCursor { class SavedCursor
{
public: public:
int cursor_col, cursor_row; int cursor_col, cursor_row;
Renditions renditions; Renditions renditions;
@@ -249,7 +252,8 @@ namespace Terminal {
SavedCursor(); SavedCursor();
}; };
class DrawState { class DrawState
{
private: private:
int width, height; int width, height;
@@ -279,7 +283,8 @@ namespace Terminal {
bool reverse_video; bool reverse_video;
bool bracketed_paste; bool bracketed_paste;
enum MouseReportingMode { enum MouseReportingMode
{
MOUSE_REPORTING_NONE = 0, MOUSE_REPORTING_NONE = 0,
MOUSE_REPORTING_X10 = 9, MOUSE_REPORTING_X10 = 9,
MOUSE_REPORTING_VT220 = 1000, MOUSE_REPORTING_VT220 = 1000,
@@ -291,7 +296,8 @@ namespace Terminal {
bool mouse_focus_event; // 1004 bool mouse_focus_event; // 1004
bool mouse_alternate_scroll; // 1007 bool mouse_alternate_scroll; // 1007
enum MouseEncodingMode { enum MouseEncodingMode
{
MOUSE_ENCODING_DEFAULT = 0, MOUSE_ENCODING_DEFAULT = 0,
MOUSE_ENCODING_UTF8 = 1005, MOUSE_ENCODING_UTF8 = 1005,
MOUSE_ENCODING_SGR = 1006, MOUSE_ENCODING_SGR = 1006,
@@ -345,15 +351,16 @@ namespace Terminal {
{ {
/* only compare fields that affect display */ /* only compare fields that affect display */
return ( width == x.width ) && ( height == x.height ) && ( cursor_col == x.cursor_col ) return ( width == x.width ) && ( height == x.height ) && ( cursor_col == x.cursor_col )
&& ( cursor_row == x.cursor_row ) && ( cursor_visible == x.cursor_visible ) && && ( cursor_row == x.cursor_row ) && ( cursor_visible == x.cursor_visible )
( reverse_video == x.reverse_video ) && ( renditions == x.renditions ) && && ( reverse_video == x.reverse_video ) && ( renditions == x.renditions )
( bracketed_paste == x.bracketed_paste ) && ( mouse_reporting_mode == x.mouse_reporting_mode ) && && ( 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_focus_event == x.mouse_focus_event ) && ( mouse_alternate_scroll == x.mouse_alternate_scroll )
( mouse_encoding_mode == x.mouse_encoding_mode ); && ( mouse_encoding_mode == x.mouse_encoding_mode );
} }
}; };
class Framebuffer { class Framebuffer
{
// To minimize copying of rows and cells, we use shared_ptr to // To minimize copying of rows and cells, we use shared_ptr to
// share unchanged rows between multiple Framebuffers. If we // share unchanged rows between multiple Framebuffers. If we
// write to a row in a Framebuffer and it is shared with other // write to a row in a Framebuffer and it is shared with other
@@ -399,22 +406,26 @@ namespace Terminal {
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(); 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 ( row == -1 )
if ( col == -1 ) col = ds.get_cursor_col(); row = ds.get_cursor_row();
if ( col == -1 )
col = ds.get_cursor_col();
return &rows.at( row )->cells.at( 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(); if ( row == -1 )
row = ds.get_cursor_row();
row_pointer& mutable_row = rows.at( row ); row_pointer& mutable_row = rows.at( row );
// If the row is shared, copy it. // If the row is shared, copy it.
if ( !mutable_row.unique() ) { if ( !mutable_row.unique() ) {
@@ -425,8 +436,10 @@ namespace Terminal {
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 ( row == -1 )
if ( col == -1 ) col = ds.get_cursor_col(); row = ds.get_cursor_row();
if ( col == -1 )
col = ds.get_cursor_col();
return &get_mutable_row( row )->cells.at( col ); return &get_mutable_row( row )->cells.at( col );
} }
@@ -465,7 +478,8 @@ namespace Terminal {
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 );
} }
}; };
} }
+30 -29
View File
@@ -36,9 +36,9 @@
#include <unistd.h> #include <unistd.h>
#include "terminaldispatcher.h"
#include "src/terminal/terminalframebuffer.h"
#include "src/terminal/parseraction.h" #include "src/terminal/parseraction.h"
#include "src/terminal/terminalframebuffer.h"
#include "terminaldispatcher.h"
using namespace Terminal; using namespace Terminal;
@@ -72,7 +72,8 @@ static void CSI_EL( Framebuffer *fb, Dispatcher *dispatch )
static Function func_CSI_EL( CSI, "K", CSI_EL ); static Function func_CSI_EL( CSI, "K", CSI_EL );
/* erase in display */ /* erase in display */
static void CSI_ED( Framebuffer *fb, Dispatcher *dispatch ) { static void CSI_ED( Framebuffer* fb, Dispatcher* dispatch )
{
switch ( dispatch->getparam( 0, 0 ) ) { switch ( dispatch->getparam( 0, 0 ) ) {
case 0: /* active position to end of screen, inclusive */ case 0: /* active position to end of screen, inclusive */
clearline( fb, -1, fb->ds.get_cursor_col(), fb->ds.get_width() - 1 ); clearline( fb, -1, fb->ds.get_cursor_col(), fb->ds.get_width() - 1 );
@@ -274,7 +275,8 @@ static void CSI_TBC( Framebuffer *fb, Dispatcher *dispatch )
/* TBC preserves wrap state */ /* TBC preserves wrap state */
static Function func_CSI_TBC( CSI, "g", CSI_TBC, false ); 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 ) { switch ( param ) {
case 1: /* cursor key mode */ case 1: /* cursor key mode */
return &( fb->ds.application_mode_cursor_keys ); return &( fb->ds.application_mode_cursor_keys );
@@ -311,7 +313,9 @@ static bool *get_DEC_mode( int param, Framebuffer *fb ) {
/* helper for CSI_DECSM and CSI_DECRM */ /* 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 */ /* set private mode */
@@ -348,7 +352,8 @@ static void CSI_DECRM( Framebuffer *fb, Dispatcher *dispatch )
static Function func_CSI_DECSM( CSI, "?h", CSI_DECSM, false ); static Function func_CSI_DECSM( CSI, "?h", CSI_DECSM, false );
static Function func_CSI_DECRM( CSI, "?l", CSI_DECRM, 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 */ if ( param == 4 ) { /* insert/replace mode */
return &( fb->ds.insert_mode ); return &( fb->ds.insert_mode );
} }
@@ -386,9 +391,7 @@ static void CSI_DECSTBM( Framebuffer *fb, Dispatcher *dispatch )
int top = dispatch->getparam( 0, 1 ); int top = dispatch->getparam( 0, 1 );
int bottom = dispatch->getparam( 1, fb->ds.get_height() ); int bottom = dispatch->getparam( 1, fb->ds.get_height() );
if ( (bottom <= top) if ( ( bottom <= top ) || ( top > fb->ds.get_height() ) || ( top == 0 && bottom == 1 ) ) {
|| (top > fb->ds.get_height())
|| (top == 0 && bottom == 1) ) {
return; /* invalid, xterm ignores */ return; /* invalid, xterm ignores */
} }
@@ -400,7 +403,8 @@ static void CSI_DECSTBM( Framebuffer *fb, Dispatcher *dispatch )
static Function func_CSI_DECSTMB( CSI, "r", CSI_DECSTBM ); static Function func_CSI_DECSTMB( CSI, "r", CSI_DECSTBM );
/* terminal bell */ /* 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(); fb->ring_bell();
} }
@@ -415,20 +419,17 @@ static void CSI_SGR( Framebuffer *fb, Dispatcher *dispatch )
because Ps of 0 in that case does not mean reset to default, even because Ps of 0 in that case does not mean reset to default, even
though it means that otherwise (as usually renditions are applied though it means that otherwise (as usually renditions are applied
in order). */ in order). */
if ((rendition == 38 || rendition == 48) && if ( ( rendition == 38 || rendition == 48 ) && ( dispatch->param_count() - i >= 3 )
(dispatch->param_count() - i >= 3) && && ( dispatch->getparam( i + 1, -1 ) == 5 ) ) {
(dispatch->getparam( i+1, -1 ) == 5)) { ( rendition == 38 ) ? fb->ds.set_foreground_color( dispatch->getparam( i + 2, 0 ) )
(rendition == 38) ? : fb->ds.set_background_color( dispatch->getparam( i + 2, 0 ) );
fb->ds.set_foreground_color( dispatch->getparam( i+2, 0 ) ) :
fb->ds.set_background_color( dispatch->getparam( i+2, 0 ) );
i += 2; i += 2;
continue; continue;
} }
/* True color support: ESC[ ... [34]8;2;<r>;<g>;<b> ... m */ /* True color support: ESC[ ... [34]8;2;<r>;<g>;<b> ... m */
if ( (rendition == 38 || rendition == 48) && if ( ( rendition == 38 || rendition == 48 ) && ( dispatch->param_count() - i >= 5 )
(dispatch->param_count() - i >= 5) && && ( dispatch->getparam( i + 1, -1 ) == 2 ) ) {
(dispatch->getparam( i+1, -1 ) == 2)) {
unsigned int red = dispatch->getparam( i + 2, 0 ); unsigned int red = dispatch->getparam( i + 2, 0 );
unsigned int green = dispatch->getparam( i + 3, 0 ); unsigned int green = dispatch->getparam( i + 3, 0 );
unsigned int blue = dispatch->getparam( i + 4, 0 ); unsigned int blue = dispatch->getparam( i + 4, 0 );
@@ -476,9 +477,7 @@ static void CSI_DSR( Framebuffer *fb, Dispatcher *dispatch )
break; break;
case 6: /* report of active position requested */ case 6: /* report of active position requested */
char cpr[32]; char cpr[32];
snprintf( cpr, 32, "\033[%d;%dR", snprintf( cpr, 32, "\033[%d;%dR", fb->ds.get_cursor_row() + 1, fb->ds.get_cursor_col() + 1 );
fb->ds.get_cursor_row() + 1,
fb->ds.get_cursor_col() + 1 );
dispatch->terminal_to_host.append( cpr ); dispatch->terminal_to_host.append( cpr );
break; break;
default: default:
@@ -593,11 +592,9 @@ static Function func_CSI_DECSTR( CSI, "!p", CSI_DECSTR );
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; */ /* handle osc copy clipboard sequence 52;c; */
if ( OSC_string.size() >= 5 && OSC_string[ 0 ] == L'5' && if ( OSC_string.size() >= 5 && OSC_string[0] == L'5' && OSC_string[1] == L'2' && OSC_string[2] == L';'
OSC_string[ 1 ] == L'2' && OSC_string[ 2 ] == L';' && && OSC_string[3] == L'c' && OSC_string[4] == L';' ) {
OSC_string[ 3 ] == L'c' && OSC_string[ 4 ] == L';') { Terminal::Framebuffer::title_type clipboard( OSC_string.begin() + 5, OSC_string.end() );
Terminal::Framebuffer::title_type clipboard(
OSC_string.begin() + 5, OSC_string.end() );
fb->set_clipboard( clipboard ); fb->set_clipboard( clipboard );
/* handle osc terminal title sequence */ /* handle osc terminal title sequence */
} else if ( OSC_string.size() >= 1 ) { } else if ( OSC_string.size() >= 1 ) {
@@ -621,8 +618,12 @@ void Dispatcher::OSC_dispatch( const Parser::OSC_End *act __attribute((unused)),
fb->set_title_initialized(); 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 ); Terminal::Framebuffer::title_type newtitle( OSC_string.begin() + offset, OSC_string.begin() + title_length );
if ( set_icon ) { fb->set_icon_name( newtitle ); } if ( set_icon ) {
if ( set_title ) { fb->set_window_title( newtitle ); } fb->set_icon_name( newtitle );
}
if ( set_title ) {
fb->set_window_title( newtitle );
}
} }
} }
} }
+2 -5
View File
@@ -36,8 +36,7 @@
using namespace Terminal; using namespace Terminal;
std::string UserInput::input( const Parser::UserByte *act, std::string UserInput::input( const Parser::UserByte* act, bool application_mode_cursor_keys )
bool application_mode_cursor_keys )
{ {
/* The user will always be in application mode. If stm is not in /* The user will always be in application mode. If stm is not in
application mode, convert user's cursor control function to an application mode, convert user's cursor control function to an
@@ -66,9 +65,7 @@ std::string UserInput::input( const Parser::UserByte *act,
case SS3: case SS3:
state = Ground; state = Ground;
if ( (!application_mode_cursor_keys) if ( ( !application_mode_cursor_keys ) && ( act->c >= 'A' ) && ( act->c <= 'D' ) ) {
&& (act->c >= 'A')
&& (act->c <= 'D') ) {
char translated_cursor[2] = { '[', act->c }; char translated_cursor[2] = { '[', act->c };
return std::string( translated_cursor, 2 ); return std::string( translated_cursor, 2 );
} else { } else {
+7 -8
View File
@@ -33,13 +33,15 @@
#ifndef TERMINALUSERINPUT_HPP #ifndef TERMINALUSERINPUT_HPP
#define TERMINALUSERINPUT_HPP #define TERMINALUSERINPUT_HPP
#include <string>
#include "src/terminal/parseraction.h" #include "src/terminal/parseraction.h"
#include <string>
namespace Terminal { namespace Terminal {
class UserInput { class UserInput
{
public: public:
enum UserInputState { enum UserInputState
{
Ground, Ground,
ESC, ESC,
SS3 SS3
@@ -49,12 +51,9 @@ namespace Terminal {
UserInputState state; UserInputState state;
public: public:
UserInput() UserInput() : state( Ground ) {}
: state( Ground )
{}
std::string input( const Parser::UserByte *act, std::string input( const Parser::UserByte* act, bool application_mode_cursor_keys );
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; }
}; };
+4 -3
View File
@@ -38,11 +38,11 @@
the Mosh project. */ the Mosh project. */
#include <cstdint> #include <cstdint>
#include <cstring>
#include <cstdlib> #include <cstdlib>
#include <cstring>
#include "src/crypto/base64.h"
#include "base64_vector.h" #include "base64_vector.h"
#include "src/crypto/base64.h"
#include "src/crypto/crypto.h" #include "src/crypto/crypto.h"
#include "src/crypto/prng.h" #include "src/crypto/prng.h"
#include "src/util/fatal_assert.h" #include "src/util/fatal_assert.h"
@@ -54,7 +54,8 @@
bool verbose = false; bool verbose = false;
static void test_base64( void ) { static void test_base64( void )
{
/* run through a test vector */ /* run through a test vector */
char encoded[25]; char encoded[25];
uint8_t decoded[16]; uint8_t decoded[16];
+5 -1
View File
@@ -1,3 +1,7 @@
struct base64_test_row { const unsigned char native[17]; const char encoded[25]; }; struct base64_test_row
{
const unsigned char native[17];
const char encoded[25];
};
typedef base64_test_row* base64_test_vector; typedef base64_test_row* base64_test_vector;
extern base64_test_row static_base64_vector[]; extern base64_test_row static_base64_vector[];
+9 -6
View File
@@ -56,7 +56,8 @@ bool verbose = false;
#define NONCE_FMT "%016" PRIx64 #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; const size_t len = prng.uint32() % MESSAGE_SIZE_MAX;
char buf[MESSAGE_SIZE_MAX]; char buf[MESSAGE_SIZE_MAX];
prng.fill( buf, len ); prng.fill( buf, len );
@@ -65,7 +66,8 @@ static std::string random_payload( void ) {
return payload; return payload;
} }
static void test_bad_decrypt( Session &decryption_session ) { static void test_bad_decrypt( Session& decryption_session )
{
std::string bad_ct = random_payload(); std::string bad_ct = random_payload();
bool got_exn = false; bool got_exn = false;
@@ -86,7 +88,8 @@ static void test_bad_decrypt( Session &decryption_session ) {
} }
/* Generate a single key and initial nonce, then perform some encryptions. */ /* 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; Base64Key key;
Session encryption_session( key ); Session encryption_session( key );
Session decryption_session( key ); Session decryption_session( key );
@@ -133,7 +136,8 @@ static void test_one_session( void ) {
} }
} }
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; verbose = true;
} }
@@ -142,8 +146,7 @@ int main( int argc, char *argv[] ) {
try { try {
test_one_session(); test_one_session();
} catch ( const CryptoException& e ) { } catch ( const CryptoException& e ) {
fprintf( stderr, "Crypto exception: %s\r\n", fprintf( stderr, "Crypto exception: %s\r\n", e.what() );
e.what() );
return 1; return 1;
} }
} }
+1 -1
View File
@@ -32,8 +32,8 @@
/* Tests that the Mosh network layer seems to be using unique nonces */ /* Tests that the Mosh network layer seems to be using unique nonces */
#include <iostream>
#include <cstdlib> #include <cstdlib>
#include <iostream>
#include <set> #include <set>
#include "src/network/network.h" #include "src/network/network.h"
+183 -159
View File
@@ -56,36 +56,45 @@ using Crypto::AlignedBuffer;
bool verbose = false; bool verbose = false;
static bool equal( const AlignedBuffer &a, const AlignedBuffer &b ) { static bool equal( const AlignedBuffer& a, const AlignedBuffer& b )
return ( a.len() == b.len() ) {
&& !memcmp( a.data(), b.data(), a.len() ); return ( a.len() == b.len() ) && !memcmp( a.data(), b.data(), a.len() );
} }
using AlignedPointer = std::shared_ptr<AlignedBuffer>; using AlignedPointer = std::shared_ptr<AlignedBuffer>;
static AlignedBuffer *get_ctx( const AlignedBuffer &key ) { static AlignedBuffer* get_ctx( const AlignedBuffer& key )
{
AlignedBuffer* ctx_buf = new AlignedBuffer( ae_ctx_sizeof() ); AlignedBuffer* ctx_buf = new AlignedBuffer( ae_ctx_sizeof() );
fatal_assert( ctx_buf ); 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; return ctx_buf;
} }
static void scrap_ctx( AlignedBuffer &ctx_buf ) { static void scrap_ctx( AlignedBuffer& ctx_buf )
{
fatal_assert( AE_SUCCESS == ae_clear( (ae_ctx*)ctx_buf.data() ) ); fatal_assert( AE_SUCCESS == ae_clear( (ae_ctx*)ctx_buf.data() ) );
} }
static void test_encrypt( const AlignedBuffer &key, const AlignedBuffer &nonce, static void test_encrypt( const AlignedBuffer& key,
const AlignedBuffer &plaintext, const AlignedBuffer &assoc, const AlignedBuffer& nonce,
const AlignedBuffer &expected_ciphertext ) { const AlignedBuffer& plaintext,
const AlignedBuffer& assoc,
const AlignedBuffer& expected_ciphertext )
{
AlignedPointer ctx_buf( get_ctx( key ) ); 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 ); AlignedBuffer observed_ciphertext( plaintext.len() + TAG_LEN );
const int ret = ae_encrypt( ctx, nonce.data(), const int ret = ae_encrypt( ctx,
plaintext.data(), plaintext.len(), nonce.data(),
assoc.data(), assoc.len(), plaintext.data(),
observed_ciphertext.data(), NULL, plaintext.len(),
assoc.data(),
assoc.len(),
observed_ciphertext.data(),
NULL,
AE_FINALIZE ); AE_FINALIZE );
if ( verbose ) { if ( verbose ) {
@@ -99,19 +108,26 @@ static void test_encrypt( const AlignedBuffer &key, const AlignedBuffer &nonce,
scrap_ctx( *ctx_buf ); scrap_ctx( *ctx_buf );
} }
static void test_decrypt( const AlignedBuffer &key, const AlignedBuffer &nonce, static void test_decrypt( const AlignedBuffer& key,
const AlignedBuffer &ciphertext, const AlignedBuffer &assoc, const AlignedBuffer& nonce,
const AlignedBuffer& ciphertext,
const AlignedBuffer& assoc,
const AlignedBuffer& expected_plaintext, const AlignedBuffer& expected_plaintext,
bool valid ) { bool valid )
{
AlignedPointer ctx_buf( get_ctx( key ) ); 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 ); AlignedBuffer observed_plaintext( ciphertext.len() - TAG_LEN );
const int ret = ae_decrypt( ctx, nonce.data(), const int ret = ae_decrypt( ctx,
ciphertext.data(), ciphertext.len(), nonce.data(),
assoc.data(), assoc.len(), ciphertext.data(),
observed_plaintext.data(), NULL, ciphertext.len(),
assoc.data(),
assoc.len(),
observed_plaintext.data(),
NULL,
AE_FINALIZE ); AE_FINALIZE );
if ( verbose ) { if ( verbose ) {
@@ -131,10 +147,15 @@ static void test_decrypt( const AlignedBuffer &key, const AlignedBuffer &nonce,
scrap_ctx( *ctx_buf ); scrap_ctx( *ctx_buf );
} }
static void test_vector( const char *key_p, const char *nonce_p, static void test_vector( const char* key_p,
size_t assoc_len, const char *assoc_p, const char* nonce_p,
size_t plaintext_len, const char *plaintext_p, size_t assoc_len,
size_t ciphertext_len, const char *ciphertext_p ) { 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 key( KEY_LEN, key_p );
AlignedBuffer nonce( NONCE_LEN, nonce_p ); AlignedBuffer nonce( NONCE_LEN, nonce_p );
@@ -150,20 +171,16 @@ static void test_vector( const char *key_p, const char *nonce_p,
hexdump( ciphertext, "exp ct" ); hexdump( ciphertext, "exp ct" );
} }
test_encrypt( key, nonce, plaintext, assoc, test_encrypt( key, nonce, plaintext, assoc, ciphertext );
ciphertext );
test_decrypt( key, nonce, ciphertext, assoc, test_decrypt( key, nonce, ciphertext, assoc, plaintext, true );
plaintext, true );
/* Try some bad ciphertexts and make sure they don't validate. */ /* Try some bad ciphertexts and make sure they don't validate. */
PRNG prng; 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() ); AlignedBuffer bad_ct( ciphertext.len(), ciphertext.data() );
( (uint8_t *) bad_ct.data() )[ prng.uint32() % bad_ct.len() ] ( (uint8_t*)bad_ct.data() )[prng.uint32() % bad_ct.len()] ^= ( 1 << ( prng.uint8() % 8 ) );
^= ( 1 << ( prng.uint8() % 8 ) ); test_decrypt( key, nonce, bad_ct, assoc, plaintext, false );
test_decrypt( key, nonce, bad_ct, assoc,
plaintext, false );
} }
if ( verbose ) { if ( verbose ) {
@@ -174,158 +191,178 @@ static void test_vector( const char *key_p, const char *nonce_p,
#define TEST_VECTOR( _key, _nonce, _assoc, _pt, _ct ) \ #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 */ /* 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_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"; const char ietf_nonce[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B";
TEST_VECTOR( ietf_key, ietf_nonce TEST_VECTOR( ietf_key,
, "" /* associated data */ ietf_nonce,
, "" /* plaintext */ "" /* associated data */
,
"" /* plaintext */
/* ciphertext including tag */ /* 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 TEST_VECTOR( ietf_key,
, "\x00\x01\x02\x03\x04\x05\x06\x07" 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" "\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" ); "\xD5\x37\x20\x9E\x8A\x96\xD1\x4E" );
TEST_VECTOR( ietf_key, ietf_nonce TEST_VECTOR( ietf_key,
, "\x00\x01\x02\x03\x04\x05\x06\x07" 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" ); "",
"\x98\xB9\x15\x52\xC8\xC0\x09\x18\x50\x44\xE3\x0A\x6E\xB2\xFE\x21" );
TEST_VECTOR( ietf_key, ietf_nonce 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" "\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" ); "\x6F\x88\xE8\x7B\x87\x1F\xBE\xED" );
TEST_VECTOR( ietf_key, ietf_nonce TEST_VECTOR( ietf_key,
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" 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" "\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" ); "\x77\x6C\x99\x24\xD6\x72\x3A\x1F\xC4\x52\x45\x32\xAC\x3E\x5B\xEB" );
TEST_VECTOR( ietf_key, ietf_nonce TEST_VECTOR( ietf_key,
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" 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" ); "",
"\x7D\xDB\x8E\x6C\xEA\x68\x14\x86\x62\x12\x50\x96\x19\xB1\x9C\xC6" );
TEST_VECTOR( ietf_key, ietf_nonce 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" "\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" ); "\x13\xCC\x8B\x74\x78\x07\x12\x1A\x4C\xBB\x3E\x4B\xD6\xB4\x56\xAF" );
TEST_VECTOR( ietf_key, ietf_nonce TEST_VECTOR( ietf_key,
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" ietf_nonce,
"\x10\x11\x12\x13\x14\x15\x16\x17" "\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" "\x10\x11\x12\x13\x14\x15\x16\x17",
"\x10\x11\x12\x13\x14\x15\x16\x17" "\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" "\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" "\xFC\xFC\xEE\x7A\x2A\x8D\x4D\x48\x5F\xA9\x4F\xC3\xF3\x88\x20\xF1"
"\xDC\x3F\x3D\x1F\xD4\xE5\x5E\x1C" ); "\xDC\x3F\x3D\x1F\xD4\xE5\x5E\x1C" );
TEST_VECTOR( ietf_key, ietf_nonce TEST_VECTOR( ietf_key,
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" ietf_nonce,
"\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",
, "\x28\x20\x26\xDA\x30\x68\xBC\x9F\xA1\x18\x68\x1D\x55\x9F\x10\xF6" ); "",
"\x28\x20\x26\xDA\x30\x68\xBC\x9F\xA1\x18\x68\x1D\x55\x9F\x10\xF6" );
TEST_VECTOR( ietf_key, ietf_nonce 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"
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22" "\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" "\xFC\xFC\xEE\x7A\x2A\x8D\x4D\x48\x6E\xF2\xF5\x25\x87\xFD\xA0\xED"
"\x97\xDC\x7E\xED\xE2\x41\xDF\x68" ); "\x97\xDC\x7E\xED\xE2\x41\xDF\x68" );
TEST_VECTOR( ietf_key, ietf_nonce TEST_VECTOR( ietf_key,
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" ietf_nonce,
"\x10\x11\x12\x13\x14\x15\x16\x17" "\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" "\x10\x11\x12\x13\x14\x15\x16\x17",
"\x10\x11\x12\x13\x14\x15\x16\x17" "\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" "\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" "\xFC\xFC\xEE\x7A\x2A\x8D\x4D\x48\x5F\xA9\x4F\xC3\xF3\x88\x20\xF1"
"\xDC\x3F\x3D\x1F\xD4\xE5\x5E\x1C" ); "\xDC\x3F\x3D\x1F\xD4\xE5\x5E\x1C" );
TEST_VECTOR( ietf_key, ietf_nonce TEST_VECTOR( ietf_key,
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17" 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"); "",
"\x28\x20\x26\xDA\x30\x68\xBC\x9F\xA1\x18\x68\x1D\x55\x9F\x10\xF6" );
TEST_VECTOR( ietf_key, ietf_nonce 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"
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22" "\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" "\xFC\xFC\xEE\x7A\x2A\x8D\x4D\x48\x6E\xF2\xF5\x25\x87\xFD\xA0\xED"
"\x97\xDC\x7E\xED\xE2\x41\xDF\x68" ); "\x97\xDC\x7E\xED\xE2\x41\xDF\x68" );
TEST_VECTOR( ietf_key, ietf_nonce TEST_VECTOR( ietf_key,
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" ietf_nonce,
"\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"
, "\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",
"\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"
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22" "\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" "\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" ); "\xB2\xA0\x40\xDD\x3B\xD5\x16\x43\x72\xD7\x6D\x7B\xB6\x82\x42\x40" );
TEST_VECTOR( ietf_key, ietf_nonce TEST_VECTOR( ietf_key,
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" ietf_nonce,
"\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",
, "\xE1\xE0\x72\x63\x3B\xAD\xE5\x1A\x60\xE8\x59\x51\xD9\xC4\x2A\x1B" ); "",
"\xE1\xE0\x72\x63\x3B\xAD\xE5\x1A\x60\xE8\x59\x51\xD9\xC4\x2A\x1B" );
TEST_VECTOR( ietf_key, ietf_nonce 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"
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22" "\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" "\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" ); "\x4A\x3B\xAE\x82\x44\x65\xCF\xDA\xF8\xC4\x1F\xC5\x0C\x7D\xF9\xD9" );
TEST_VECTOR( ietf_key, ietf_nonce TEST_VECTOR( ietf_key,
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" 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" "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
"\x20\x21\x22\x23\x24\x25\x26\x27" "\x20\x21\x22\x23\x24\x25\x26\x27",
, "\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"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
"\x20\x21\x22\x23\x24\x25\x26\x27" "\x20\x21\x22\x23\x24\x25\x26\x27",
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22" "\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" "\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" "\x68\xC6\x57\x78\xB0\x58\xA6\x35\x65\x9C\x62\x32\x11\xDE\xEA\x0D"
"\xE3\x0D\x2C\x38\x18\x79\xF4\xC8" ); "\xE3\x0D\x2C\x38\x18\x79\xF4\xC8" );
TEST_VECTOR( ietf_key, ietf_nonce TEST_VECTOR( ietf_key,
, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" 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" "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
"\x20\x21\x22\x23\x24\x25\x26\x27" "\x20\x21\x22\x23\x24\x25\x26\x27",
, "" "",
, "\x7A\xEB\x7A\x69\xA1\x68\x7D\xD0\x82\xCA\x27\xB0\xD9\xA3\x70\x96" ); "\x7A\xEB\x7A\x69\xA1\x68\x7D\xD0\x82\xCA\x27\xB0\xD9\xA3\x70\x96" );
TEST_VECTOR( ietf_key, ietf_nonce 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"
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
"\x20\x21\x22\x23\x24\x25\x26\x27" "\x20\x21\x22\x23\x24\x25\x26\x27",
, "\xBE\xA5\xE8\x79\x8D\xBE\x71\x10\x03\x1C\x14\x4D\xA0\xB2\x61\x22" "\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" "\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" "\x68\xC6\x57\x78\xB0\x58\xA6\x35\x06\x0C\x84\x67\xF4\xAB\xAB\x5E"
"\x8B\x3C\x20\x67\xA2\xE1\x15\xDC" ); "\x8B\x3C\x20\x67\xA2\xE1\x15\xDC" );
/* Some big texts. These were originally encrypted using this program; /* Some big texts. These were originally encrypted using this program;
they are regression tests. */ they are regression tests. */
TEST_VECTOR( TEST_VECTOR( "\x06\xF8\x9F\x69\xDA\x49\xDA\xD7\x68\x48\xFF\xB3\x60\xB6\x8F\x00",
"\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",
, "\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"
, "\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" "\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" "\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" "\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" "\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" "\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" "\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" "\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" "\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" "\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" "\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" "\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" "\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" ); "\x1b\xa1\xac\x6e\x7a\x8a\xa0\x20\x3d\xeb\x29\x8b\xf4\x55\x41\x62" );
TEST_VECTOR( TEST_VECTOR( "\x7A\x54\x0D\x3E\x56\x38\xF7\xC6\xCF\xAB\xF9\x56\xDC\xCA\x14\x23",
"\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",
, "\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"
, "\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" "\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" "\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" "\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" "\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" "\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" "\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" "\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" "\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" "\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" "\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" "\xd7\x11\xa1\xf2\xcb\x09\x6f\xf0\x14\x3c\x3f\xf2\xc7\x79\xfb\x3f"
@@ -465,7 +501,8 @@ static void test_all_vectors( void ) {
/* http://tools.ietf.org/html/draft-krovetz-ocb-03#appendix-A /* http://tools.ietf.org/html/draft-krovetz-ocb-03#appendix-A
also specifies an iterative test algorithm, which we implement here. */ 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 */ /* Key is always all zeros */
AlignedBuffer key( KEY_LEN ); AlignedBuffer key( KEY_LEN );
memset( key.data(), 0, KEY_LEN ); memset( key.data(), 0, KEY_LEN );
@@ -493,29 +530,18 @@ static void test_iterative( void ) {
AlignedBuffer out( s.len() + TAG_LEN ); AlignedBuffer out( s.len() + TAG_LEN );
/* OCB-ENCRYPT(K,N,S,S) */ /* OCB-ENCRYPT(K,N,S,S) */
fatal_assert( 0 <= ae_encrypt( ctx, nonce.data(), fatal_assert(
s.data(), s.len(), 0 <= ae_encrypt( ctx, nonce.data(), s.data(), s.len(), s.data(), s.len(), out.data(), NULL, AE_FINALIZE ) );
s.data(), s.len(),
out.data(), NULL,
AE_FINALIZE ) );
memcpy( acc, out.data(), s.len() + TAG_LEN ); memcpy( acc, out.data(), s.len() + TAG_LEN );
acc += s.len() + TAG_LEN; acc += s.len() + TAG_LEN;
/* OCB-ENCRYPT(K,N,<empty string>,S) */ /* OCB-ENCRYPT(K,N,<empty string>,S) */
fatal_assert( 0 <= ae_encrypt( ctx, nonce.data(), fatal_assert( 0 <= ae_encrypt( ctx, nonce.data(), s.data(), s.len(), NULL, 0, out.data(), NULL, AE_FINALIZE ) );
s.data(), s.len(),
NULL, 0,
out.data(), NULL,
AE_FINALIZE ) );
memcpy( acc, out.data(), s.len() + TAG_LEN ); memcpy( acc, out.data(), s.len() + TAG_LEN );
acc += s.len() + TAG_LEN; acc += s.len() + TAG_LEN;
/* OCB-ENCRYPT(K,N,S,<empty string>) */ /* OCB-ENCRYPT(K,N,S,<empty string>) */
fatal_assert( 0 <= ae_encrypt( ctx, nonce.data(), fatal_assert( 0 <= ae_encrypt( ctx, nonce.data(), NULL, 0, s.data(), s.len(), out.data(), NULL, AE_FINALIZE ) );
NULL, 0,
s.data(), s.len(),
out.data(), NULL,
AE_FINALIZE ) );
memcpy( acc, out.data(), TAG_LEN ); memcpy( acc, out.data(), TAG_LEN );
acc += TAG_LEN; acc += TAG_LEN;
} }
@@ -523,11 +549,9 @@ static void test_iterative( void ) {
/* OCB-ENCRYPT(K,N,C,<empty string>) */ /* OCB-ENCRYPT(K,N,C,<empty string>) */
AlignedBuffer out( TAG_LEN ); AlignedBuffer out( TAG_LEN );
memset( nonce.data(), 0, NONCE_LEN ); memset( nonce.data(), 0, NONCE_LEN );
fatal_assert( 0 <= ae_encrypt( ctx, nonce.data(), fatal_assert(
NULL, 0, 0 <= ae_encrypt(
accumulator.data(), accumulator.len(), ctx, nonce.data(), NULL, 0, accumulator.data(), accumulator.len(), out.data(), NULL, AE_FINALIZE ) );
out.data(), NULL,
AE_FINALIZE ) );
/* Check this final tag against the known value */ /* 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" ); AlignedBuffer correct( TAG_LEN, "\xB2\xB4\x1C\xBF\x9B\x05\x03\x7D\xA7\xF1\x6C\x24\xA3\x5C\x1C\x94" );
+6 -3
View File
@@ -34,7 +34,8 @@
#include "test_utils.h" #include "test_utils.h"
void hexdump( const void *buf, size_t len, const char *name ) { void hexdump( const void* buf, size_t len, const char* name )
{
const unsigned char* data = (const unsigned char*)buf; const unsigned char* data = (const unsigned char*)buf;
printf( DUMP_NAME_FMT, name ); printf( DUMP_NAME_FMT, name );
for ( size_t i = 0; i < len; i++ ) { for ( size_t i = 0; i < len; i++ ) {
@@ -46,10 +47,12 @@ void hexdump( const void *buf, size_t len, const char *name ) {
printf( "\n" ); 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 ); 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 ); hexdump( buf.data(), buf.size(), name );
} }
+8 -6
View File
@@ -41,14 +41,16 @@
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]; char buffer[2048];
snprintf( buffer, 2048, "Illegal counterparty input (possible denial of service) in function %s at %s:%d, failed test: %s\n", snprintf( buffer,
function, file, line, expression ); 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 ); throw Crypto::CryptoException( buffer );
} }
#define dos_assert(expr) \ #define dos_assert( expr ) ( ( expr ) ? (void)0 : dos_detected( #expr, __FILE__, __LINE__, __func__ ) )
((expr) \
? (void)0 \
: dos_detected (#expr, __FILE__, __LINE__, __func__ ))
#endif #endif
+7 -6
View File
@@ -38,14 +38,15 @@
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", fprintf( stderr,
function, file, line, expression ); "Fatal assertion failure in function %s at %s:%d\nFailed test: %s\n",
function,
file,
line,
expression );
abort(); abort();
} }
#define fatal_assert(expr) \ #define fatal_assert( expr ) ( ( expr ) ? (void)0 : fatal_error( #expr, __FILE__, __LINE__, __func__ ) )
((expr) \
? (void)0 \
: fatal_error (#expr, __FILE__, __LINE__, __func__ ))
#endif #endif
+8 -8
View File
@@ -45,7 +45,6 @@
#include "src/util/locale_utils.h" #include "src/util/locale_utils.h"
const std::string LocaleVar::str( void ) const const std::string LocaleVar::str( void ) const
{ {
if ( name.empty() ) { if ( name.empty() ) {
@@ -81,16 +80,17 @@ const char *locale_charset( void )
return ret; return ret;
} }
bool is_utf8_locale( void ) { bool is_utf8_locale( void )
{
/* Verify locale calls for UTF-8 */ /* Verify locale calls for UTF-8 */
if ( strcmp( locale_charset(), "UTF-8" ) != 0 && if ( strcmp( locale_charset(), "UTF-8" ) != 0 && strcmp( locale_charset(), "utf-8" ) != 0 ) {
strcmp( locale_charset(), "utf-8" ) != 0 ) {
return false; return false;
} }
return true; return true;
} }
void set_native_locale( void ) { void set_native_locale( void )
{
/* Adopt native locale */ /* Adopt native locale */
if ( NULL == setlocale( LC_ALL, "" ) ) { if ( NULL == setlocale( LC_ALL, "" ) ) {
int saved_errno = errno; int saved_errno = errno;
@@ -98,8 +98,7 @@ void set_native_locale( void ) {
LocaleVar ctype( get_ctype() ); LocaleVar ctype( get_ctype() );
fprintf( stderr, "The locale requested by %s isn't available here.\n", ctype.str().c_str() ); fprintf( stderr, "The locale requested by %s isn't available here.\n", ctype.str().c_str() );
if ( !ctype.name.empty() ) { if ( !ctype.name.empty() ) {
fprintf( stderr, "Running `locale-gen %s' may be necessary.\n\n", fprintf( stderr, "Running `locale-gen %s' may be necessary.\n\n", ctype.value.c_str() );
ctype.value.c_str() );
} }
} else { } else {
errno = saved_errno; 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( "LANG" );
unsetenv( "LANGUAGE" ); unsetenv( "LANGUAGE" );
unsetenv( "LC_CTYPE" ); unsetenv( "LC_CTYPE" );
+3 -4
View File
@@ -35,12 +35,11 @@
#include <string> #include <string>
class LocaleVar { class LocaleVar
{
public: public:
const std::string name, value; const std::string name, value;
LocaleVar( const char *s_name, const char *s_value ) LocaleVar( const char* s_name, const char* s_value ) : name( s_name ), value( s_value ) {}
: name( s_name ), value( s_value )
{}
const std::string str( void ) const; const std::string str( void ) const;
}; };
+3 -7
View File
@@ -46,9 +46,7 @@
#include "src/util/pty_compat.h" #include "src/util/pty_compat.h"
#ifndef HAVE_FORKPTY #ifndef HAVE_FORKPTY
pid_t my_forkpty( int *amaster, char *name, pid_t my_forkpty( int* amaster, char* name, const struct termios* termp, const struct winsize* winp )
const struct termios *termp,
const struct winsize *winp )
{ {
/* For Solaris and AIX */ /* For Solaris and AIX */
int master, slave; int master, slave;
@@ -94,8 +92,7 @@ pid_t my_forkpty( int *amaster, char *name,
} }
#ifndef _AIX #ifndef _AIX
if ( ioctl(slave, I_PUSH, "ptem") < 0 || if ( ioctl( slave, I_PUSH, "ptem" ) < 0 || ioctl( slave, I_PUSH, "ldterm" ) < 0 ) {
ioctl(slave, I_PUSH, "ldterm") < 0 ) {
perror( "ioctl(I_PUSH)" ); perror( "ioctl(I_PUSH)" );
close( slave ); close( slave );
close( master ); close( master );
@@ -172,8 +169,7 @@ pid_t my_forkpty( int *amaster, char *name,
#ifndef HAVE_CFMAKERAW #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 termios_p->c_iflag &= ~( IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON );
| INLCR | IGNCR | ICRNL | IXON);
termios_p->c_oflag &= ~OPOST; termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~( ECHO | ECHONL | ICANON | ISIG | IEXTEN ); termios_p->c_lflag &= ~( ECHO | ECHONL | ICANON | ISIG | IEXTEN );
termios_p->c_cflag &= ~( CSIZE | PARENB ); termios_p->c_cflag &= ~( CSIZE | PARENB );
+1 -3
View File
@@ -42,9 +42,7 @@
#define cfmakeraw my_cfmakeraw #define cfmakeraw my_cfmakeraw
#endif #endif
pid_t my_forkpty( int *amaster, char *name, pid_t my_forkpty( int* amaster, char* name, const struct termios* termp, const struct winsize* winp );
const struct termios *termp,
const struct winsize *winp );
void my_cfmakeraw( struct termios* termios_p ); void my_cfmakeraw( struct termios* termios_p );
+12 -13
View File
@@ -48,9 +48,11 @@
Any signals blocked by calling sigprocmask() outside this code will still be Any signals blocked by calling sigprocmask() outside this code will still be
received during Select::select(). So don't do that. */ received during Select::select(). So don't do that. */
class Select { class Select
{
public: public:
static Select &get_instance( void ) { static Select& get_instance( void )
{
/* COFU may or may not be thread-safe, depending on compiler */ /* COFU may or may not be thread-safe, depending on compiler */
static Select instance; static Select instance;
return instance; return instance;
@@ -61,10 +63,8 @@ private:
: max_fd( -1 ) : max_fd( -1 )
/* These initializations are not used; they are just /* These initializations are not used; they are just
here to appease -Weffc++. */ here to appease -Weffc++. */
, all_fds( dummy_fd_set ) ,
, read_fds( dummy_fd_set ) all_fds( dummy_fd_set ), read_fds( dummy_fd_set ), empty_sigset( dummy_sigset ), consecutive_polls( 0 )
, empty_sigset( dummy_sigset )
, consecutive_polls( 0 )
{ {
FD_ZERO( &all_fds ); FD_ZERO( &all_fds );
FD_ZERO( &read_fds ); FD_ZERO( &read_fds );
@@ -75,8 +75,7 @@ private:
void clear_got_signal( void ) void clear_got_signal( void )
{ {
for ( volatile sig_atomic_t *p = got_signal; for ( volatile sig_atomic_t* p = got_signal; p < got_signal + sizeof( got_signal ) / sizeof( *got_signal );
p < got_signal + sizeof( got_signal ) / sizeof( *got_signal );
p++ ) { p++ ) {
*p = 0; *p = 0;
} }
@@ -95,10 +94,7 @@ public:
FD_SET( fd, &all_fds ); FD_SET( fd, &all_fds );
} }
void clear_fds( void ) void clear_fds( void ) { FD_ZERO( &all_fds ); }
{
FD_ZERO( &all_fds );
}
static void add_signal( int signum ) static void add_signal( int signum )
{ {
@@ -220,7 +216,10 @@ public:
return rv; 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: private:
static const int MAX_SIGNAL_NUMBER = 64; static const int MAX_SIGNAL_NUMBER = 64;
+1 -2
View File
@@ -42,8 +42,7 @@ int swrite( int fd, const char *str, ssize_t len )
ssize_t total_bytes_written = 0; 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 ) { while ( total_bytes_written < bytes_to_write ) {
ssize_t bytes_written = write( fd, str + total_bytes_written, ssize_t bytes_written = write( fd, str + total_bytes_written, bytes_to_write - total_bytes_written );
bytes_to_write - total_bytes_written );
if ( bytes_written <= 0 ) { if ( bytes_written <= 0 ) {
perror( "write" ); perror( "write" );
return -1; return -1;
+1 -1
View File
@@ -44,8 +44,8 @@
#include <mach/mach_time.h> #include <mach/mach_time.h>
#endif #endif
#if HAVE_GETTIMEOFDAY #if HAVE_GETTIMEOFDAY
#include <sys/time.h>
#include <cstdio> #include <cstdio>
#include <sys/time.h>
#endif #endif
// On Apple systems CLOCK_MONOTONIC is unfortunately able to go // On Apple systems CLOCK_MONOTONIC is unfortunately able to go