LCOV - code coverage report
Current view: top level - src/network - transportfragment.cc (source / functions) Hit Total Coverage
Test: mosh-1.3.2 Code Coverage Lines: 93 99 93.9 %
Date: 2022-02-06 20:19:53 Functions: 7 8 87.5 %
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 <assert.h>
      34             : 
      35             : #include "byteorder.h"
      36             : #include "transportfragment.h"
      37             : #include "transportinstruction.pb.h"
      38             : #include "compressor.h"
      39             : #include "fatal_assert.h"
      40             : 
      41             : using namespace Network;
      42             : using namespace TransportBuffers;
      43             : 
      44        5333 : static string network_order_string( uint16_t host_order )
      45             : {
      46        5333 :   uint16_t net_int = htobe16( host_order );
      47        5333 :   return string( (char *)&net_int, sizeof( net_int ) );
      48             : }
      49             : 
      50        5333 : static string network_order_string( uint64_t host_order )
      51             : {
      52        5333 :   uint64_t net_int = htobe64( host_order );
      53        5333 :   return string( (char *)&net_int, sizeof( net_int ) );
      54             : }
      55             : 
      56        5333 : string Fragment::tostring( void )
      57             : {
      58        5333 :   assert( initialized );
      59             : 
      60        5333 :   string ret;
      61             :   
      62       10666 :   ret += network_order_string( id );
      63             : 
      64        5333 :   fatal_assert( !( fragment_num & 0x8000 ) ); /* effective limit on size of a terminal screen change or buffered user input */
      65        5333 :   uint16_t combined_fragment_num = ( final << 15 ) | fragment_num;
      66       10666 :   ret += network_order_string( combined_fragment_num );
      67             : 
      68        5333 :   assert( ret.size() == frag_header_len );
      69             : 
      70        5333 :   ret += contents;
      71             : 
      72        5333 :   return ret;
      73           0 : }
      74             : 
      75        5285 : Fragment::Fragment( const string &x )
      76        5285 :   : id( -1 ), fragment_num( -1 ), final( false ), initialized( true ),
      77        5285 :     contents()
      78             : {
      79        5285 :   fatal_assert( x.size() >= frag_header_len );
      80        5285 :   contents = string( x.begin() + frag_header_len, x.end() );
      81             : 
      82        5285 :   uint64_t data64;
      83        5285 :   uint16_t *data16 = (uint16_t *)x.data();
      84        5285 :   memcpy( &data64, x.data(), sizeof( data64 ) );
      85        5285 :   id = be64toh( data64 );
      86        5285 :   fragment_num = be16toh( data16[ 4 ] );
      87        5285 :   final = ( fragment_num & 0x8000 ) >> 15;
      88        5285 :   fragment_num &= 0x7FFF;
      89        5285 : }
      90             : 
      91        5285 : bool FragmentAssembly::add_fragment( Fragment &frag )
      92             : {
      93             :   /* see if this is a totally new packet */
      94        5285 :   if ( current_id != frag.id ) {
      95        5281 :     fragments.clear();
      96        5281 :     fragments.resize( frag.fragment_num + 1 );
      97        5281 :     fragments.at( frag.fragment_num ) = frag;
      98        5281 :     fragments_arrived = 1;
      99        5281 :     fragments_total = -1; /* unknown */
     100        5281 :     current_id = frag.id;
     101             :  } else { /* not a new packet */
     102             :     /* see if we already have this fragment */
     103           4 :     if ( (fragments.size() > frag.fragment_num)
     104           4 :          && (fragments.at( frag.fragment_num ).initialized) ) {
     105             :       /* make sure new version is same as what we already have */
     106           0 :       assert( fragments.at( frag.fragment_num ) == frag );
     107             :     } else {
     108           4 :       if ( (int)fragments.size() < frag.fragment_num + 1 ) {
     109           4 :         fragments.resize( frag.fragment_num + 1 );
     110             :       }
     111           4 :       fragments.at( frag.fragment_num ) = frag;
     112           4 :       fragments_arrived++;
     113             :     }
     114             :   }
     115             : 
     116        5285 :   if ( frag.final ) {
     117        5281 :     fragments_total = frag.fragment_num + 1;
     118        5281 :     assert( (int)fragments.size() <= fragments_total );
     119        5281 :     fragments.resize( fragments_total );
     120             :   }
     121             : 
     122        5285 :   if ( fragments_total != -1 ) {
     123        5281 :     assert( fragments_arrived <= fragments_total );
     124             :   }
     125             : 
     126             :   /* see if we're done */
     127        5285 :   return fragments_arrived == fragments_total;
     128             : }
     129             : 
     130        5281 : Instruction FragmentAssembly::get_assembly( void )
     131             : {
     132        5281 :   assert( fragments_arrived == fragments_total );
     133             : 
     134        5281 :   string encoded;
     135             : 
     136       10566 :   for ( int i = 0; i < fragments_total; i++ ) {
     137        5285 :     assert( fragments.at( i ).initialized );
     138       10570 :     encoded += fragments.at( i ).contents;
     139             :   }
     140             : 
     141        5281 :   Instruction ret;
     142        5281 :   fatal_assert( ret.ParseFromString( get_compressor().uncompress_str( encoded ) ) );
     143             : 
     144        5281 :   fragments.clear();
     145        5281 :   fragments_arrived = 0;
     146        5281 :   fragments_total = -1;
     147             : 
     148        5281 :   return ret;
     149        5281 : }
     150             : 
     151           0 : bool Fragment::operator==( const Fragment &x ) const
     152             : {
     153           0 :   return ( id == x.id ) && ( fragment_num == x.fragment_num ) && ( final == x.final )
     154           0 :     && ( initialized == x.initialized ) && ( contents == x.contents );
     155             : }
     156             : 
     157        5329 : vector<Fragment> Fragmenter::make_fragments( const Instruction &inst, size_t MTU )
     158             : {
     159        5329 :   MTU -= Fragment::frag_header_len;
     160        5329 :   if ( (inst.old_num() != last_instruction.old_num())
     161        1974 :        || (inst.new_num() != last_instruction.new_num())
     162         202 :        || (inst.ack_num() != last_instruction.ack_num())
     163         202 :        || (inst.throwaway_num() != last_instruction.throwaway_num())
     164         202 :        || (inst.chaff() != last_instruction.chaff())
     165           0 :        || (inst.protocol_version() != last_instruction.protocol_version())
     166        5329 :        || (last_MTU != MTU) ) {
     167        5329 :     next_instruction_id++;
     168             :   }
     169             : 
     170        5329 :   if ( (inst.old_num() == last_instruction.old_num())
     171        5329 :        && (inst.new_num() == last_instruction.new_num()) ) {
     172         202 :     assert( inst.diff() == last_instruction.diff() );
     173             :   }
     174             : 
     175        5329 :   last_instruction = inst;
     176        5329 :   last_MTU = MTU;
     177             : 
     178        5329 :   string payload = get_compressor().compress_str( inst.SerializeAsString() );
     179        5329 :   uint16_t fragment_num = 0;
     180        5329 :   vector<Fragment> ret;
     181             : 
     182       10662 :   while ( !payload.empty() ) {
     183        5333 :     string this_fragment;
     184        5333 :     bool final = false;
     185             : 
     186        5333 :     if ( payload.size() > MTU ) {
     187           4 :       this_fragment = string( payload.begin(), payload.begin() + MTU );
     188           8 :       payload = string( payload.begin() + MTU, payload.end() );
     189             :     } else {
     190        5329 :       this_fragment = payload;
     191        5329 :       payload.clear();
     192        5329 :       final = true;
     193             :     }
     194             : 
     195       10666 :     ret.push_back( Fragment( next_instruction_id, fragment_num++, final, this_fragment ) );
     196        5333 :   }
     197             : 
     198        5329 :   return ret;
     199        5329 : }

Generated by: LCOV version 1.14