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 
34 #ifndef TRANSPORT_SENDER_HPP
35 #define TRANSPORT_SENDER_HPP
36 
37 #include <string>
38 #include <list>
39 
40 #include "network.h"
41 #include "transportinstruction.pb.h"
42 #include "transportstate.h"
43 #include "transportfragment.h"
44 #include "prng.h"
45 
46 using std::list;
47 using std::pair;
48 using namespace TransportBuffers;
49 
50 namespace Network {
51   /* timing parameters */
52   const int SEND_INTERVAL_MIN = 20; /* ms between frames */
53   const int SEND_INTERVAL_MAX = 250; /* ms between frames */
54   const int ACK_INTERVAL = 3000; /* ms between empty acks */
55   const int ACK_DELAY = 100; /* ms before delayed ack */
56   const int SHUTDOWN_RETRIES = 16; /* number of shutdown packets to send before giving up */
57   const int ACTIVE_RETRY_TIMEOUT = 10000; /* attempt to resend at frame rate */
58 
59   template <class MyState>
60   class TransportSender
61   {
62   private:
63     /* helper methods for tick() */
64     void update_assumed_receiver_state( void );
65     void attempt_prospective_resend_optimization( string &proposed_diff );
66     void rationalize_states( void );
67     void send_to_receiver( const string & diff );
68     void send_empty_ack( void );
69     void send_in_fragments( const string & diff, uint64_t new_num );
70     void add_sent_state( uint64_t the_timestamp, uint64_t num, MyState &state );
71 
72     /* state of sender */
73     Connection *connection;
74 
75     MyState current_state;
76 
77     typedef list< TimestampedState<MyState> > sent_states_type;
78     sent_states_type sent_states;
79     /* first element: known, acknowledged receiver state */
80     /* last element: last sent state */
81 
82     /* somewhere in the middle: the assumed state of the receiver */
83     typename sent_states_type::iterator assumed_receiver_state;
84 
85     /* for fragment creation */
86     Fragmenter fragmenter;
87 
88     /* timing state */
89     uint64_t next_ack_time;
90     uint64_t next_send_time;
91 
92     void calculate_timers( void );
93 
94     unsigned int verbose;
95     bool shutdown_in_progress;
96     int shutdown_tries;
97     uint64_t shutdown_start;
98 
99     /* information about receiver state */
100     uint64_t ack_num;
101     bool pending_data_ack;
102 
103     unsigned int SEND_MINDELAY; /* ms to collect all input */
104 
105     uint64_t last_heard; /* last time received new state */
106 
107     /* chaff to disguise instruction length */
108     PRNG prng;
109     const string make_chaff( void );
110 
111     uint64_t mindelay_clock; /* time of first pending change to current state */
112 
113   public:
114     /* constructor */
115     TransportSender( Connection *s_connection, MyState &initial_state );
116 
117     /* Send data or an ack if necessary */
118     void tick( void );
119 
120     /* Returns the number of ms to wait until next possible event. */
121     int wait_time( void );
122 
123     /* Executed upon receipt of ack */
124     void process_acknowledgment_through( uint64_t ack_num );
125 
126     /* Executed upon entry to new receiver state */
127     void set_ack_num( uint64_t s_ack_num );
128 
129     /* Accelerate reply ack */
set_data_ack(void)130     void set_data_ack( void ) { pending_data_ack = true; }
131 
132     /* Received something */
remote_heard(uint64_t ts)133     void remote_heard( uint64_t ts ) { last_heard = ts; }
134 
135     /* Starts shutdown sequence */
start_shutdown(void)136     void start_shutdown( void ) { if ( !shutdown_in_progress ) { shutdown_start = timestamp(); shutdown_in_progress = true; } }
137 
138     /* Misc. getters and setters */
139     /* Cannot modify current_state while shutdown in progress */
get_current_state(void)140     MyState &get_current_state( void ) { assert( !shutdown_in_progress ); return current_state; }
set_current_state(const MyState & x)141     void set_current_state( const MyState &x )
142     {
143       assert( !shutdown_in_progress );
144       current_state = x;
145       current_state.reset_input();
146     }
set_verbose(unsigned int s_verbose)147     void set_verbose( unsigned int s_verbose ) { verbose = s_verbose; }
148 
get_shutdown_in_progress(void)149     bool get_shutdown_in_progress( void ) const { return shutdown_in_progress; }
get_shutdown_acknowledged(void)150     bool get_shutdown_acknowledged( void ) const { return sent_states.front().num == uint64_t(-1); }
get_counterparty_shutdown_acknowledged(void)151     bool get_counterparty_shutdown_acknowledged( void ) const { return fragmenter.last_ack_sent() == uint64_t(-1); }
get_sent_state_acked_timestamp(void)152     uint64_t get_sent_state_acked_timestamp( void ) const { return sent_states.front().timestamp; }
get_sent_state_acked(void)153     uint64_t get_sent_state_acked( void ) const { return sent_states.front().num; }
get_sent_state_last(void)154     uint64_t get_sent_state_last( void ) const { return sent_states.back().num; }
155 
156     bool shutdown_ack_timed_out( void ) const;
157 
set_send_delay(int new_delay)158     void set_send_delay( int new_delay ) { SEND_MINDELAY = new_delay; }
159 
160     unsigned int send_interval( void ) const;
161 
162     /* nonexistent methods to satisfy -Weffc++ */
163     TransportSender( const TransportSender &x );
164     TransportSender & operator=( const TransportSender &x );
165   };
166 }
167 
168 #endif
169