LCOV - code coverage report
Current view: top level - src/statesync - completeterminal.cc (source / functions) Hit Total Coverage
Test: mosh-1.3.2 Code Coverage Lines: 92 98 93.9 %
Date: 2022-02-06 20:19:53 Functions: 10 10 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :     Mosh: the mobile shell
       3             :     Copyright 2012 Keith Winstein
       4             : 
       5             :     This program is free software: you can redistribute it and/or modify
       6             :     it under the terms of the GNU General Public License as published by
       7             :     the Free Software Foundation, either version 3 of the License, or
       8             :     (at your option) any later version.
       9             : 
      10             :     This program is distributed in the hope that it will be useful,
      11             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :     GNU General Public License for more details.
      14             : 
      15             :     You should have received a copy of the GNU General Public License
      16             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17             : 
      18             :     In addition, as a special exception, the copyright holders give
      19             :     permission to link the code of portions of this program with the
      20             :     OpenSSL library under certain conditions as described in each
      21             :     individual source file, and distribute linked combinations including
      22             :     the two.
      23             : 
      24             :     You must obey the GNU General Public License in all respects for all
      25             :     of the code used other than OpenSSL. If you modify file(s) with this
      26             :     exception, you may extend this exception to your version of the
      27             :     file(s), but you are not obligated to do so. If you do not wish to do
      28             :     so, delete this exception statement from your version. If you delete
      29             :     this exception statement from all source files in the program, then
      30             :     also delete it here.
      31             : */
      32             : 
      33             : #include "completeterminal.h"
      34             : #include "fatal_assert.h"
      35             : 
      36             : #include "hostinput.pb.h"
      37             : 
      38             : #include <limits.h>
      39             : 
      40             : using namespace std;
      41             : using namespace Parser;
      42             : using namespace Terminal;
      43             : using namespace HostBuffers;
      44             : 
      45       26916 : string Complete::act( const string &str )
      46             : {
      47    72216454 :   for ( unsigned int i = 0; i < str.size(); i++ ) {
      48             :     /* parse octet into up to three actions */
      49    72189538 :     parser.input( str[ i ], actions );
      50             :     
      51             :     /* apply actions to terminal and delete them */
      52   144377982 :     for ( Actions::iterator it = actions.begin();
      53   144377982 :           it != actions.end();
      54   144377982 :           it++ ) {
      55    72188444 :       Action &act = **it;
      56    72188444 :       act.act_on_terminal( &terminal );
      57             :     }
      58    72189538 :     actions.clear();
      59             :   }
      60             : 
      61       26916 :   return terminal.read_octets_to_host();
      62             : }
      63             : 
      64        1765 : string Complete::act( const Action &act )
      65             : {
      66             :   /* apply action to terminal */
      67        1765 :   act.act_on_terminal( &terminal );
      68        1765 :   return terminal.read_octets_to_host();
      69             : }
      70             : 
      71             : /* interface for Network::Transport */
      72       18191 : string Complete::diff_from( const Complete &existing ) const
      73             : {
      74       18191 :   HostBuffers::HostMessage output;
      75             : 
      76       18191 :   if ( existing.get_echo_ack() != get_echo_ack() ) {
      77        9479 :     assert( get_echo_ack() >= existing.get_echo_ack() );
      78        9479 :     Instruction *new_echo = output.add_instruction();
      79        9479 :     new_echo->MutableExtension( echoack )->set_echo_ack_num( get_echo_ack() );
      80             :   }
      81             : 
      82       18191 :   if ( !(existing.get_fb() == get_fb()) ) {
      83       17215 :     if ( (existing.get_fb().ds.get_width() != terminal.get_fb().ds.get_width())
      84       17215 :          || (existing.get_fb().ds.get_height() != terminal.get_fb().ds.get_height()) ) {
      85          88 :       Instruction *new_res = output.add_instruction();
      86          88 :       new_res->MutableExtension( resize )->set_width( terminal.get_fb().ds.get_width() );
      87          88 :       new_res->MutableExtension( resize )->set_height( terminal.get_fb().ds.get_height() );
      88             :     }
      89       17215 :     string update = display.new_frame( true, existing.get_fb(), terminal.get_fb() );
      90       17215 :     if ( !update.empty() ) {
      91       13302 :       Instruction *new_inst = output.add_instruction();
      92       30517 :       new_inst->MutableExtension( hostbytes )->set_hoststring( update );
      93             :     }
      94       17215 :   }
      95             :   
      96       36382 :   return output.SerializeAsString();
      97       18191 : }
      98             : 
      99       10754 : string Complete::init_diff( void ) const
     100             : {
     101       10754 :   return diff_from( Complete( get_fb().ds.get_width(), get_fb().ds.get_height() ));
     102             : }
     103             : 
     104        8078 : void Complete::apply_string( const string & diff )
     105             : {
     106        8078 :   HostBuffers::HostMessage input;
     107        8078 :   fatal_assert( input.ParseFromString( diff ) );
     108             : 
     109       14381 :   for ( int i = 0; i < input.instruction_size(); i++ ) {
     110        6303 :     if ( input.instruction( i ).HasExtension( hostbytes ) ) {
     111        5460 :       string terminal_to_host = act( input.instruction( i ).GetExtension( hostbytes ).hoststring() );
     112        5460 :       assert( terminal_to_host.empty() ); /* server never interrogates client terminal */
     113        6303 :     } else if ( input.instruction( i ).HasExtension( resize ) ) {
     114         264 :       act( Resize( input.instruction( i ).GetExtension( resize ).width(),
     115          88 :                                       input.instruction( i ).GetExtension( resize ).height() ) );
     116         755 :     } else if ( input.instruction( i ).HasExtension( echoack ) ) {
     117         755 :       uint64_t inst_echo_ack_num = input.instruction( i ).GetExtension( echoack ).echo_ack_num();
     118         755 :       assert( inst_echo_ack_num >= echo_ack );
     119         755 :       echo_ack = inst_echo_ack_num;
     120             :     }
     121             :   }
     122        8078 : }
     123             : 
     124       67291 : bool Complete::operator==( Complete const &x ) const
     125             : {
     126             :   //  assert( parser == x.parser ); /* parser state is irrelevant for us */
     127       67291 :   return (terminal == x.terminal) && (echo_ack == x.echo_ack);
     128             : }
     129             : 
     130       26592 : bool Complete::set_echo_ack( uint64_t now )
     131             : {
     132       26592 :   bool ret = false;
     133       26592 :   uint64_t newest_echo_ack = 0;
     134             : 
     135       55006 :   for ( input_history_type::const_iterator i = input_history.begin();
     136       55006 :         i != input_history.end();
     137       55006 :         i++ ) {
     138       28414 :     if ( i->second <= now - ECHO_TIMEOUT ) {
     139       25148 :       newest_echo_ack = i->first;
     140             :     }
     141             :   }
     142             : 
     143             :   for ( input_history_type::iterator i = input_history.begin();
     144       55006 :         i != input_history.end(); ) {
     145       28414 :     input_history_type::iterator i_next = i;
     146       28414 :     i_next++;
     147       28414 :     if ( i->first < newest_echo_ack ) {
     148         308 :       input_history.erase( i );
     149             :     }
     150             :     i = i_next;
     151             :   }
     152             : 
     153       26592 :   if ( echo_ack != newest_echo_ack ) {
     154         734 :     ret = true;
     155             :   }
     156             : 
     157       26592 :   echo_ack = newest_echo_ack;
     158             : 
     159       26592 :   return ret;
     160             : }
     161             : 
     162         958 : void Complete::register_input_frame( uint64_t n, uint64_t now )
     163             : {
     164         958 :   input_history.push_back( std::make_pair( n, now ) );
     165         958 : }
     166             : 
     167       27044 : int Complete::wait_time( uint64_t now ) const
     168             : {
     169       27044 :   if ( input_history.size() < 2 ) {
     170             :     return INT_MAX;
     171             :   }
     172             : 
     173        1508 :   input_history_type::const_iterator it = input_history.begin();
     174        1508 :   it++;
     175             : 
     176        1508 :   uint64_t next_echo_ack_time = it->second + ECHO_TIMEOUT;
     177        1508 :   if ( next_echo_ack_time <= now ) {
     178             :     return 0;
     179             :   }
     180        1508 :   return next_echo_ack_time - now;
     181             : }
     182             : 
     183        5377 : bool Complete::compare( const Complete &other ) const
     184             : {
     185        5377 :   bool ret = false;
     186        5377 :   const Framebuffer &fb = terminal.get_fb();
     187        5377 :   const Framebuffer &other_fb = other.terminal.get_fb();
     188        5377 :   const int height = fb.ds.get_height();
     189        5377 :   const int other_height = other_fb.ds.get_height();
     190        5377 :   const int width = fb.ds.get_width();
     191        5377 :   const int other_width = other_fb.ds.get_width();
     192             : 
     193        5377 :   if ( height != other_height || width != other_width ) {
     194           0 :     fprintf( stderr, "Framebuffer size (%dx%d, %dx%d) differs.\n", width, height, other_width, other_height );
     195           0 :     return true;
     196             :   }
     197             : 
     198      134105 :   for ( int y = 0; y < height; y++ ) {
     199    10384728 :     for ( int x = 0; x < width; x++ ) {
     200    10256000 :       if ( fb.get_cell( y, x )->compare( *other_fb.get_cell( y, x ) ) ) {
     201           0 :         fprintf( stderr, "Cell (%d, %d) differs.\n", y, x );
     202           0 :         ret = true;
     203             :       }
     204             :     }
     205             :   }
     206             : 
     207        5377 :   if ( (fb.ds.get_cursor_row() != other_fb.ds.get_cursor_row())
     208        5377 :        || (fb.ds.get_cursor_col() != other_fb.ds.get_cursor_col()) ) {
     209           0 :     fprintf( stderr, "Cursor mismatch: (%d, %d) vs. (%d, %d).\n",
     210             :              fb.ds.get_cursor_row(), fb.ds.get_cursor_col(),
     211             :              other_fb.ds.get_cursor_row(), other_fb.ds.get_cursor_col() );
     212           0 :     ret = true;
     213             :   }
     214             :   /* XXX should compare other terminal state too (mouse mode, bell. etc.) */
     215             : 
     216             :   return ret;
     217             : }

Generated by: LCOV version 1.14