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
|