LCOV - code coverage report
Current view: top level - src/network - networktransport-impl.h (source / functions) Hit Total Coverage
Test: mosh-1.3.2 Code Coverage Lines: 74 88 84.1 %
Date: 2022-02-06 20:19:53 Functions: 7 7 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             : #ifndef NETWORK_TRANSPORT_IMPL_HPP
      34             : #define NETWORK_TRANSPORT_IMPL_HPP
      35             : 
      36             : #include "networktransport.h"
      37             : 
      38             : #include "transportsender-impl.h"
      39             : 
      40             : using namespace Network;
      41             : 
      42             : template <class MyState, class RemoteState>
      43         452 : Transport<MyState, RemoteState>::Transport( MyState &initial_state, RemoteState &initial_remote,
      44             :                                             const char *desired_ip, const char *desired_port )
      45         452 :   : connection( desired_ip, desired_port ),
      46         452 :     sender( &connection, initial_state ),
      47        1356 :     received_states( 1, TimestampedState<RemoteState>( timestamp(), 0, initial_remote ) ),
      48         452 :     receiver_quench_timer( 0 ),
      49         452 :     last_receiver_state( initial_remote ),
      50         452 :     fragments(),
      51         452 :     verbose( 0 )
      52             : {
      53             :   /* server */
      54         452 : }
      55             : 
      56             : template <class MyState, class RemoteState>
      57         448 : Transport<MyState, RemoteState>::Transport( MyState &initial_state, RemoteState &initial_remote,
      58             :                                             const char *key_str, const char *ip, const char *port )
      59         448 :   : connection( key_str, ip, port ),
      60         448 :     sender( &connection, initial_state ),
      61        1344 :     received_states( 1, TimestampedState<RemoteState>( timestamp(), 0, initial_remote ) ),
      62         448 :     receiver_quench_timer( 0 ),
      63         448 :     last_receiver_state( initial_remote ),
      64         448 :     fragments(),
      65         448 :     verbose( 0 )
      66             : {
      67             :   /* client */
      68         448 : }
      69             : 
      70             : template <class MyState, class RemoteState>
      71        5285 : void Transport<MyState, RemoteState>::recv( void )
      72             : {
      73        5285 :   string s( connection.recv() );
      74        5285 :   Fragment frag( s );
      75             : 
      76        5285 :   if ( fragments.add_fragment( frag ) ) { /* complete packet */
      77        5281 :     Instruction inst = fragments.get_assembly();
      78             : 
      79        5281 :     if ( inst.protocol_version() != MOSH_PROTOCOL_VERSION ) {
      80           0 :       throw NetworkException( "mosh protocol version mismatch", 0 );
      81             :     }
      82             : 
      83        5281 :     sender.process_acknowledgment_through( inst.ack_num() );
      84             : 
      85             :     /* inform network layer of roundtrip (end-to-end-to-end) connectivity */
      86        5281 :     connection.set_last_roundtrip_success( sender.get_sent_state_acked_timestamp() );
      87             : 
      88             :     /* first, make sure we don't already have the new state */
      89       18849 :     for ( typename list< TimestampedState<RemoteState> >::iterator i = received_states.begin();
      90       18849 :           i != received_states.end();
      91       18849 :           i++ ) {
      92       13740 :       if ( inst.new_num() == i->num ) {
      93         172 :         return;
      94             :       }
      95             :     }
      96             :     
      97             :     /* now, make sure we do have the old state */
      98        9164 :     bool found = 0;
      99             :     typename list< TimestampedState<RemoteState> >::iterator reference_state = received_states.begin();
     100        9164 :     while ( reference_state != received_states.end() ) {
     101        9164 :       if ( inst.old_num() == reference_state->num ) {
     102             :         found = true;
     103             :         break;
     104             :       }
     105        9164 :       reference_state++;
     106             :     }
     107             :     
     108        5109 :     if ( !found ) {
     109             :       //    fprintf( stderr, "Ignoring out-of-order packet. Reference state %d has been discarded or hasn't yet been received.\n", int(inst.old_num) );
     110             :       return; /* this is security-sensitive and part of how we enforce idempotency */
     111             :     }
     112             :     
     113             :     /* Do not accept state if our queue is full */
     114             :     /* This is better than dropping states from the middle of the
     115             :        queue (as sender does), because we don't want to ACK a state
     116             :        and then discard it later. */
     117             : 
     118        5109 :     process_throwaway_until( inst.throwaway_num() );
     119             : 
     120        5109 :     if ( received_states.size() > 1024 ) { /* limit on state queue */
     121           0 :       uint64_t now = timestamp();
     122           0 :       if ( now < receiver_quench_timer ) { /* deny letting state grow further */
     123           0 :         if ( verbose ) {
     124           0 :           fprintf( stderr, "[%u] Receiver queue full, discarding %d (malicious sender or long-unidirectional connectivity?)\n",
     125           0 :                    (unsigned int)(timestamp() % 100000), (int)inst.new_num() );
     126             :         }
     127           0 :         return;
     128             :       } else {
     129           0 :         receiver_quench_timer = now + 15000;
     130             :       }
     131             :     }
     132             : 
     133             :     /* apply diff to reference state */
     134        5109 :     TimestampedState<RemoteState> new_state = *reference_state;
     135        5109 :     new_state.timestamp = timestamp();
     136        5109 :     new_state.num = inst.new_num();
     137             : 
     138        5109 :     if ( !inst.diff().empty() ) {
     139        3659 :       new_state.state.apply_string( inst.diff() );
     140             :     }
     141             : 
     142             :     /* Insert new state in sorted place */
     143       14497 :     for ( typename list< TimestampedState<RemoteState> >::iterator i = received_states.begin();
     144       14497 :           i != received_states.end();
     145       14497 :           i++ ) {
     146        9388 :       if ( i->num > new_state.num ) {
     147           0 :         received_states.insert( i, new_state );
     148           0 :         if ( verbose ) {
     149           0 :           fprintf( stderr, "[%u] Received OUT-OF-ORDER state %d [ack %d]\n",
     150           0 :                    (unsigned int)(timestamp() % 100000), (int)new_state.num, (int)inst.ack_num() );
     151             :         }
     152           0 :         return;
     153             :       }
     154             :     }
     155        5109 :     if ( verbose ) {
     156        8993 :       fprintf( stderr, "[%u] Received state %d [coming from %d, ack %d]\n",
     157        1942 :                (unsigned int)(timestamp() % 100000), (int)new_state.num, (int)inst.old_num(), (int)inst.ack_num() );
     158             :     }
     159        5109 :     received_states.push_back( new_state );
     160        5109 :     sender.set_ack_num( received_states.back().num );
     161             : 
     162        5109 :     sender.remote_heard( new_state.timestamp );
     163        5109 :     if ( !inst.diff().empty() ) {
     164        5109 :       sender.set_data_ack();
     165             :     }
     166        5281 :   }
     167       10570 : }
     168             : 
     169             : /* The sender uses throwaway_num to tell us the earliest received state that we need to keep around */
     170             : template <class MyState, class RemoteState>
     171        5109 : void Transport<MyState, RemoteState>::process_throwaway_until( uint64_t throwaway_num )
     172             : {
     173        5109 :   typename list< TimestampedState<RemoteState> >::iterator i = received_states.begin();
     174       18498 :   while ( i != received_states.end() ) {
     175       13389 :     typename list< TimestampedState<RemoteState> >::iterator inext = i;
     176       13389 :     inext++;
     177       13389 :     if ( i->num < throwaway_num ) {
     178        4001 :       received_states.erase( i );
     179             :     }
     180             :     i = inext;
     181             :   }
     182             : 
     183        5109 :   fatal_assert( received_states.size() > 0 );
     184        5109 : }
     185             : 
     186             : template <class MyState, class RemoteState>
     187        1946 : string Transport<MyState, RemoteState>::get_remote_diff( void )
     188             : {
     189             :   /* find diff between last receiver state and current remote state, then rationalize states */
     190             : 
     191        1946 :   string ret( received_states.back().state.diff_from( last_receiver_state ) );
     192             : 
     193        1946 :   const RemoteState *oldest_receiver_state = &received_states.front().state;
     194             : 
     195        5903 :   for ( typename list< TimestampedState<RemoteState> >::reverse_iterator i = received_states.rbegin();
     196        5903 :         i != received_states.rend();
     197             :         i++ ) {
     198        3957 :     i->state.subtract( oldest_receiver_state );
     199             :   }  
     200             : 
     201        1946 :   last_receiver_state = received_states.back().state;
     202             : 
     203        1946 :   return ret;
     204           0 : }
     205             : 
     206             : #endif

Generated by: LCOV version 1.14