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:
committed by
Alex Chernyakhovsky
parent
0b15dc94fa
commit
3acaa1c4d3
+1
-5
@@ -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.
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -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 ) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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" ) ) {
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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() );
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 );
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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; }
|
||||||
|
|
||||||
|
|||||||
@@ -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 );
|
||||||
|
|||||||
@@ -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 ); }
|
||||||
|
|
||||||
|
|||||||
@@ -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() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 );
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 );
|
||||||
|
|||||||
@@ -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.) */
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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 );
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 );
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 );
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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() );
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
@@ -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];
|
||||||
|
|||||||
@@ -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[];
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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" );
|
||||||
|
|||||||
@@ -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 );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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" );
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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 );
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user