Coverage Report

Created: 2024-05-16 12:16

/__w/smoldot/smoldot/repo/lib/src/libp2p/connection/single_stream_handshake.rs
Line
Count
Source (jump to first uncovered line)
1
// Smoldot
2
// Copyright (C) 2019-2022  Parity Technologies (UK) Ltd.
3
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
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
//! State machine handling the handshake with a TCP or WebSocket libp2p connection.
19
//!
20
//! A connection handshake consists of three steps:
21
//!
22
//! - A multistream-select negotiation to negotiate the encryption protocol. Only the noise
23
//! protocol is supported at the moment.
24
//! - A noise protocol handshake, where public keys are exchanged and symmetric encryption is
25
//! initialized.
26
//! - A multistream-select negotiation to negotiate the Yamux protocol. Only the Yamux protocol is
27
//! supported at the moment. This negotiation is performed on top of the noise cipher.
28
//!
29
//! This entire handshake requires in total either three or five TCP packets (not including the
30
//! TCP handshake), depending on the strategy used for the multistream-select protocol.
31
32
// TODO: finish commenting on the number of round trips
33
// TODO: some round-trips can be removed: the multistream-select ones, and maybe also a Noise one, but it's complicated
34
35
use super::{
36
    super::peer_id::PeerId,
37
    super::read_write::ReadWrite,
38
    established::ConnectionPrototype,
39
    multistream_select,
40
    noise::{self, NoiseKey},
41
    yamux,
42
};
43
44
use alloc::boxed::Box;
45
use core::fmt;
46
47
mod tests;
48
49
/// Current state of a connection handshake.
50
#[derive(Debug, derive_more::From)]
51
pub enum Handshake {
52
    /// Connection handshake in progress.
53
    Healthy(HealthyHandshake),
54
    /// Handshake has succeeded. Connection is now open.
55
    Success {
56
        /// Network identity of the remote.
57
        remote_peer_id: PeerId,
58
        /// Prototype for the connection.
59
        connection: ConnectionPrototype,
60
    },
61
}
62
63
impl Handshake {
64
    /// Shortcut for [`HealthyHandshake::noise_yamux`] wrapped in a [`Handshake`].
65
16
    pub fn noise_yamux(
66
16
        noise_key: &NoiseKey,
67
16
        noise_ephemeral_secret_key: &[u8; 32],
68
16
        is_initiator: bool,
69
16
    ) -> Self {
70
16
        HealthyHandshake::noise_yamux(noise_key, noise_ephemeral_secret_key, is_initiator).into()
71
16
    }
_RNvMNtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection23single_stream_handshakeNtB2_9Handshake11noise_yamux
Line
Count
Source
65
16
    pub fn noise_yamux(
66
16
        noise_key: &NoiseKey,
67
16
        noise_ephemeral_secret_key: &[u8; 32],
68
16
        is_initiator: bool,
69
16
    ) -> Self {
70
16
        HealthyHandshake::noise_yamux(noise_key, noise_ephemeral_secret_key, is_initiator).into()
71
16
    }
Unexecuted instantiation: _RNvMNtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection23single_stream_handshakeNtB2_9Handshake11noise_yamux
72
}
73
74
/// Connection handshake in progress.
75
pub struct HealthyHandshake {
76
    state: NegotiationState,
77
}
78
79
enum NegotiationState {
80
    EncryptionProtocol {
81
        negotiation: multistream_select::InProgress<&'static str>,
82
        /// Handshake that will be driven after the protocol negotiation is successful. Created
83
        /// ahead of time but not actually used.
84
        handshake: noise::HandshakeInProgress,
85
    },
86
    Encryption {
87
        handshake: noise::HandshakeInProgress,
88
    },
89
    Multiplexing {
90
        peer_id: PeerId,
91
        encryption: Box<noise::Noise>,
92
        negotiation: multistream_select::InProgress<&'static str>,
93
    },
94
}
95
96
impl HealthyHandshake {
97
    /// Initializes a new state machine for a Noise + Yamux handshake.
98
    ///
99
    /// Must pass `true` for `is_initiator` if the connection has been opened by the local machine,
100
    /// or `false` if it has been opened by the remote.
101
    ///
102
    /// The Noise ephemeral secret key must never be re-used.
103
16
    pub fn noise_yamux(
104
16
        noise_key: &NoiseKey,
105
16
        noise_ephemeral_secret_key: &[u8; 32],
106
16
        is_initiator: bool,
107
16
    ) -> Self {
108
16
        let negotiation = multistream_select::InProgress::new(if is_initiator {
109
8
            multistream_select::Config::Dialer {
110
8
                requested_protocol: noise::PROTOCOL_NAME,
111
8
            }
112
        } else {
113
8
            multistream_select::Config::Listener {
114
8
                max_protocol_name_len: noise::PROTOCOL_NAME.len(),
115
8
            }
116
        });
117
118
16
        HealthyHandshake {
119
16
            state: NegotiationState::EncryptionProtocol {
120
16
                negotiation,
121
16
                handshake: noise::HandshakeInProgress::new(noise::Config {
122
16
                    key: noise_key,
123
16
                    is_initiator,
124
16
                    prologue: &[],
125
16
                    ephemeral_secret_key: noise_ephemeral_secret_key,
126
16
                }),
127
16
            },
128
16
        }
129
16
    }
_RNvMs_NtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection23single_stream_handshakeNtB4_16HealthyHandshake11noise_yamux
Line
Count
Source
103
16
    pub fn noise_yamux(
104
16
        noise_key: &NoiseKey,
105
16
        noise_ephemeral_secret_key: &[u8; 32],
106
16
        is_initiator: bool,
107
16
    ) -> Self {
108
16
        let negotiation = multistream_select::InProgress::new(if is_initiator {
109
8
            multistream_select::Config::Dialer {
110
8
                requested_protocol: noise::PROTOCOL_NAME,
111
8
            }
112
        } else {
113
8
            multistream_select::Config::Listener {
114
8
                max_protocol_name_len: noise::PROTOCOL_NAME.len(),
115
8
            }
116
        });
117
118
16
        HealthyHandshake {
119
16
            state: NegotiationState::EncryptionProtocol {
120
16
                negotiation,
121
16
                handshake: noise::HandshakeInProgress::new(noise::Config {
122
16
                    key: noise_key,
123
16
                    is_initiator,
124
16
                    prologue: &[],
125
16
                    ephemeral_secret_key: noise_ephemeral_secret_key,
126
16
                }),
127
16
            },
128
16
        }
129
16
    }
Unexecuted instantiation: _RNvMs_NtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection23single_stream_handshakeNtB4_16HealthyHandshake11noise_yamux
130
131
    /// Feeds data coming from a socket and writes back data to send up.
132
    ///
133
    /// On success, returns the new state of the negotiation.
134
    ///
135
    /// An error is returned if the protocol is being violated by the remote. When that happens,
136
    /// the connection should be closed altogether.
137
64
    pub fn read_write<TNow: Clone>(
138
64
        mut self,
139
64
        read_write: &mut ReadWrite<TNow>,
140
64
    ) -> Result<Handshake, HandshakeError> {
141
112
        loop {
142
112
            match self.state {
143
                NegotiationState::EncryptionProtocol {
144
32
                    negotiation,
145
32
                    handshake,
146
                } => {
147
                    // Earliest point of the handshake. The encryption is being negotiated.
148
                    // Delegating read/write to the negotiation.
149
32
                    let updated = negotiation
150
32
                        .read_write(read_write)
151
32
                        .map_err(HandshakeError::EncryptionMultistreamSelect)
?0
;
152
153
32
                    return match updated {
154
8
                        multistream_select::Negotiation::InProgress(updated) => {
155
8
                            Ok(Handshake::Healthy(HealthyHandshake {
156
8
                                state: NegotiationState::EncryptionProtocol {
157
8
                                    negotiation: updated,
158
8
                                    handshake,
159
8
                                },
160
8
                            }))
161
                        }
162
                        multistream_select::Negotiation::Success => {
163
16
                            self.state = NegotiationState::Encryption { handshake };
164
16
                            continue;
165
                        }
166
8
                        multistream_select::Negotiation::ListenerAcceptOrDeny(accept_reject) => {
167
8
                            let negotiation =
168
8
                                if accept_reject.requested_protocol() == noise::PROTOCOL_NAME {
169
8
                                    accept_reject.accept()
170
                                } else {
171
0
                                    accept_reject.reject()
172
                                };
173
8
                            self.state = NegotiationState::EncryptionProtocol {
174
8
                                negotiation,
175
8
                                handshake,
176
8
                            };
177
8
                            continue;
178
                        }
179
                        multistream_select::Negotiation::NotAvailable => {
180
0
                            Err(HandshakeError::NoEncryptionProtocol)
181
                        }
182
                    };
183
                }
184
185
40
                NegotiationState::Encryption { handshake } => {
186
                    // Delegating read/write to the Noise handshake state machine.
187
40
                    let updated = handshake.read_write(read_write).map_err(|err| {
188
0
                        debug_assert!(!matches!(err, noise::HandshakeError::WriteClosed));
189
0
                        HandshakeError::NoiseHandshake(err)
190
40
                    })
?0
;
Unexecuted instantiation: _RNCINvMs_NtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection23single_stream_handshakeNtB7_16HealthyHandshake10read_writeNtNtCsaYZPK01V26L_4core4time8DurationE0Bd_
Unexecuted instantiation: _RNCINvMs_NtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection23single_stream_handshakeNtB7_16HealthyHandshake10read_writelE0Bd_
Unexecuted instantiation: _RNCINvMs_NtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection23single_stream_handshakeNtB7_16HealthyHandshake10read_writeNtNtCsaYZPK01V26L_4core4time8DurationE0CsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs_NtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection23single_stream_handshakeNtB7_16HealthyHandshake10read_writepE0Bd_
Unexecuted instantiation: _RNCINvMs_NtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection23single_stream_handshakeNtB7_16HealthyHandshake10read_writeNtNtCsbpXXxgr6u8g_3std4time7InstantE0CsiUjFBJteJ7x_17smoldot_full_node
191
192
40
                    match updated {
193
                        noise::NoiseHandshake::Success {
194
16
                            cipher,
195
16
                            remote_peer_id,
196
                        } => {
197
                            // Encryption layer has been successfully negotiated. Start the
198
                            // handshake for the multiplexing protocol negotiation.
199
16
                            let negotiation =
200
16
                                multistream_select::InProgress::new(if cipher.is_initiator() {
201
8
                                    multistream_select::Config::Dialer {
202
8
                                        requested_protocol: yamux::PROTOCOL_NAME,
203
8
                                    }
204
                                } else {
205
8
                                    multistream_select::Config::Listener {
206
8
                                        max_protocol_name_len: yamux::PROTOCOL_NAME.len(),
207
8
                                    }
208
                                });
209
210
16
                            self.state = NegotiationState::Multiplexing {
211
16
                                peer_id: remote_peer_id,
212
16
                                encryption: Box::new(cipher),
213
16
                                negotiation,
214
16
                            };
215
16
216
16
                            continue;
217
                        }
218
24
                        noise::NoiseHandshake::InProgress(updated) => {
219
24
                            return Ok(Handshake::Healthy(HealthyHandshake {
220
24
                                state: NegotiationState::Encryption { handshake: updated },
221
24
                            }));
222
                        }
223
                    };
224
                }
225
226
                NegotiationState::Multiplexing {
227
40
                    negotiation,
228
40
                    mut encryption,
229
40
                    peer_id,
230
40
                } => {
231
40
                    // During the multiplexing protocol negotiation, all exchanges have to go
232
40
                    // through the Noise cipher.
233
40
234
40
                    if read_write.expected_incoming_bytes.is_none() {
235
0
                        return Err(HandshakeError::MultiplexingMultistreamSelect(
236
0
                            multistream_select::Error::ReadClosed,
237
0
                        ));
238
40
                    }
239
40
                    if read_write.write_bytes_queueable.is_none() {
240
0
                        return Err(HandshakeError::MultiplexingMultistreamSelect(
241
0
                            multistream_select::Error::WriteClosed,
242
0
                        ));
243
40
                    }
244
245
40
                    let negotiation_update = {
246
40
                        let mut decrypted_stream = encryption
247
40
                            .read_write(read_write)
248
40
                            .map_err(HandshakeError::Noise)
?0
;
249
40
                        negotiation
250
40
                            .read_write(&mut *decrypted_stream)
251
40
                            .map_err(HandshakeError::MultiplexingMultistreamSelect)
?0
252
                    };
253
254
40
                    return match negotiation_update {
255
16
                        multistream_select::Negotiation::InProgress(updated) => {
256
16
                            Ok(Handshake::Healthy(HealthyHandshake {
257
16
                                state: NegotiationState::Multiplexing {
258
16
                                    negotiation: updated,
259
16
                                    encryption,
260
16
                                    peer_id,
261
16
                                },
262
16
                            }))
263
                        }
264
8
                        multistream_select::Negotiation::ListenerAcceptOrDeny(accept_reject) => {
265
8
                            let negotiation =
266
8
                                if accept_reject.requested_protocol() == yamux::PROTOCOL_NAME {
267
8
                                    accept_reject.accept()
268
                                } else {
269
0
                                    accept_reject.reject()
270
                                };
271
8
                            self.state = NegotiationState::Multiplexing {
272
8
                                peer_id,
273
8
                                encryption,
274
8
                                negotiation,
275
8
                            };
276
8
                            continue;
277
                        }
278
16
                        multistream_select::Negotiation::Success => Ok(Handshake::Success {
279
16
                            connection: ConnectionPrototype::from_noise_yamux(*encryption),
280
16
                            remote_peer_id: peer_id,
281
16
                        }),
282
                        multistream_select::Negotiation::NotAvailable => {
283
0
                            Err(HandshakeError::NoMultiplexingProtocol)
284
                        }
285
                    };
286
                }
287
            }
288
        }
289
64
    }
_RINvMs_NtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection23single_stream_handshakeNtB5_16HealthyHandshake10read_writeNtNtCsaYZPK01V26L_4core4time8DurationEBb_
Line
Count
Source
137
56
    pub fn read_write<TNow: Clone>(
138
56
        mut self,
139
56
        read_write: &mut ReadWrite<TNow>,
140
56
    ) -> Result<Handshake, HandshakeError> {
141
98
        loop {
142
98
            match self.state {
143
                NegotiationState::EncryptionProtocol {
144
28
                    negotiation,
145
28
                    handshake,
146
                } => {
147
                    // Earliest point of the handshake. The encryption is being negotiated.
148
                    // Delegating read/write to the negotiation.
149
28
                    let updated = negotiation
150
28
                        .read_write(read_write)
151
28
                        .map_err(HandshakeError::EncryptionMultistreamSelect)
?0
;
152
153
28
                    return match updated {
154
7
                        multistream_select::Negotiation::InProgress(updated) => {
155
7
                            Ok(Handshake::Healthy(HealthyHandshake {
156
7
                                state: NegotiationState::EncryptionProtocol {
157
7
                                    negotiation: updated,
158
7
                                    handshake,
159
7
                                },
160
7
                            }))
161
                        }
162
                        multistream_select::Negotiation::Success => {
163
14
                            self.state = NegotiationState::Encryption { handshake };
164
14
                            continue;
165
                        }
166
7
                        multistream_select::Negotiation::ListenerAcceptOrDeny(accept_reject) => {
167
7
                            let negotiation =
168
7
                                if accept_reject.requested_protocol() == noise::PROTOCOL_NAME {
169
7
                                    accept_reject.accept()
170
                                } else {
171
0
                                    accept_reject.reject()
172
                                };
173
7
                            self.state = NegotiationState::EncryptionProtocol {
174
7
                                negotiation,
175
7
                                handshake,
176
7
                            };
177
7
                            continue;
178
                        }
179
                        multistream_select::Negotiation::NotAvailable => {
180
0
                            Err(HandshakeError::NoEncryptionProtocol)
181
                        }
182
                    };
183
                }
184
185
35
                NegotiationState::Encryption { handshake } => {
186
                    // Delegating read/write to the Noise handshake state machine.
187
35
                    let updated = handshake.read_write(read_write).map_err(|err| {
188
                        debug_assert!(!matches!(err, noise::HandshakeError::WriteClosed));
189
                        HandshakeError::NoiseHandshake(err)
190
35
                    })
?0
;
191
192
35
                    match updated {
193
                        noise::NoiseHandshake::Success {
194
14
                            cipher,
195
14
                            remote_peer_id,
196
                        } => {
197
                            // Encryption layer has been successfully negotiated. Start the
198
                            // handshake for the multiplexing protocol negotiation.
199
14
                            let negotiation =
200
14
                                multistream_select::InProgress::new(if cipher.is_initiator() {
201
7
                                    multistream_select::Config::Dialer {
202
7
                                        requested_protocol: yamux::PROTOCOL_NAME,
203
7
                                    }
204
                                } else {
205
7
                                    multistream_select::Config::Listener {
206
7
                                        max_protocol_name_len: yamux::PROTOCOL_NAME.len(),
207
7
                                    }
208
                                });
209
210
14
                            self.state = NegotiationState::Multiplexing {
211
14
                                peer_id: remote_peer_id,
212
14
                                encryption: Box::new(cipher),
213
14
                                negotiation,
214
14
                            };
215
14
216
14
                            continue;
217
                        }
218
21
                        noise::NoiseHandshake::InProgress(updated) => {
219
21
                            return Ok(Handshake::Healthy(HealthyHandshake {
220
21
                                state: NegotiationState::Encryption { handshake: updated },
221
21
                            }));
222
                        }
223
                    };
224
                }
225
226
                NegotiationState::Multiplexing {
227
35
                    negotiation,
228
35
                    mut encryption,
229
35
                    peer_id,
230
35
                } => {
231
35
                    // During the multiplexing protocol negotiation, all exchanges have to go
232
35
                    // through the Noise cipher.
233
35
234
35
                    if read_write.expected_incoming_bytes.is_none() {
235
0
                        return Err(HandshakeError::MultiplexingMultistreamSelect(
236
0
                            multistream_select::Error::ReadClosed,
237
0
                        ));
238
35
                    }
239
35
                    if read_write.write_bytes_queueable.is_none() {
240
0
                        return Err(HandshakeError::MultiplexingMultistreamSelect(
241
0
                            multistream_select::Error::WriteClosed,
242
0
                        ));
243
35
                    }
244
245
35
                    let negotiation_update = {
246
35
                        let mut decrypted_stream = encryption
247
35
                            .read_write(read_write)
248
35
                            .map_err(HandshakeError::Noise)
?0
;
249
35
                        negotiation
250
35
                            .read_write(&mut *decrypted_stream)
251
35
                            .map_err(HandshakeError::MultiplexingMultistreamSelect)
?0
252
                    };
253
254
35
                    return match negotiation_update {
255
14
                        multistream_select::Negotiation::InProgress(updated) => {
256
14
                            Ok(Handshake::Healthy(HealthyHandshake {
257
14
                                state: NegotiationState::Multiplexing {
258
14
                                    negotiation: updated,
259
14
                                    encryption,
260
14
                                    peer_id,
261
14
                                },
262
14
                            }))
263
                        }
264
7
                        multistream_select::Negotiation::ListenerAcceptOrDeny(accept_reject) => {
265
7
                            let negotiation =
266
7
                                if accept_reject.requested_protocol() == yamux::PROTOCOL_NAME {
267
7
                                    accept_reject.accept()
268
                                } else {
269
0
                                    accept_reject.reject()
270
                                };
271
7
                            self.state = NegotiationState::Multiplexing {
272
7
                                peer_id,
273
7
                                encryption,
274
7
                                negotiation,
275
7
                            };
276
7
                            continue;
277
                        }
278
14
                        multistream_select::Negotiation::Success => Ok(Handshake::Success {
279
14
                            connection: ConnectionPrototype::from_noise_yamux(*encryption),
280
14
                            remote_peer_id: peer_id,
281
14
                        }),
282
                        multistream_select::Negotiation::NotAvailable => {
283
0
                            Err(HandshakeError::NoMultiplexingProtocol)
284
                        }
285
                    };
286
                }
287
            }
288
        }
289
56
    }
_RINvMs_NtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection23single_stream_handshakeNtB5_16HealthyHandshake10read_writelEBb_
Line
Count
Source
137
8
    pub fn read_write<TNow: Clone>(
138
8
        mut self,
139
8
        read_write: &mut ReadWrite<TNow>,
140
8
    ) -> Result<Handshake, HandshakeError> {
141
14
        loop {
142
14
            match self.state {
143
                NegotiationState::EncryptionProtocol {
144
4
                    negotiation,
145
4
                    handshake,
146
                } => {
147
                    // Earliest point of the handshake. The encryption is being negotiated.
148
                    // Delegating read/write to the negotiation.
149
4
                    let updated = negotiation
150
4
                        .read_write(read_write)
151
4
                        .map_err(HandshakeError::EncryptionMultistreamSelect)
?0
;
152
153
4
                    return match updated {
154
1
                        multistream_select::Negotiation::InProgress(updated) => {
155
1
                            Ok(Handshake::Healthy(HealthyHandshake {
156
1
                                state: NegotiationState::EncryptionProtocol {
157
1
                                    negotiation: updated,
158
1
                                    handshake,
159
1
                                },
160
1
                            }))
161
                        }
162
                        multistream_select::Negotiation::Success => {
163
2
                            self.state = NegotiationState::Encryption { handshake };
164
2
                            continue;
165
                        }
166
1
                        multistream_select::Negotiation::ListenerAcceptOrDeny(accept_reject) => {
167
1
                            let negotiation =
168
1
                                if accept_reject.requested_protocol() == noise::PROTOCOL_NAME {
169
1
                                    accept_reject.accept()
170
                                } else {
171
0
                                    accept_reject.reject()
172
                                };
173
1
                            self.state = NegotiationState::EncryptionProtocol {
174
1
                                negotiation,
175
1
                                handshake,
176
1
                            };
177
1
                            continue;
178
                        }
179
                        multistream_select::Negotiation::NotAvailable => {
180
0
                            Err(HandshakeError::NoEncryptionProtocol)
181
                        }
182
                    };
183
                }
184
185
5
                NegotiationState::Encryption { handshake } => {
186
                    // Delegating read/write to the Noise handshake state machine.
187
5
                    let updated = handshake.read_write(read_write).map_err(|err| {
188
                        debug_assert!(!matches!(err, noise::HandshakeError::WriteClosed));
189
                        HandshakeError::NoiseHandshake(err)
190
5
                    })
?0
;
191
192
5
                    match updated {
193
                        noise::NoiseHandshake::Success {
194
2
                            cipher,
195
2
                            remote_peer_id,
196
                        } => {
197
                            // Encryption layer has been successfully negotiated. Start the
198
                            // handshake for the multiplexing protocol negotiation.
199
2
                            let negotiation =
200
2
                                multistream_select::InProgress::new(if cipher.is_initiator() {
201
1
                                    multistream_select::Config::Dialer {
202
1
                                        requested_protocol: yamux::PROTOCOL_NAME,
203
1
                                    }
204
                                } else {
205
1
                                    multistream_select::Config::Listener {
206
1
                                        max_protocol_name_len: yamux::PROTOCOL_NAME.len(),
207
1
                                    }
208
                                });
209
210
2
                            self.state = NegotiationState::Multiplexing {
211
2
                                peer_id: remote_peer_id,
212
2
                                encryption: Box::new(cipher),
213
2
                                negotiation,
214
2
                            };
215
2
216
2
                            continue;
217
                        }
218
3
                        noise::NoiseHandshake::InProgress(updated) => {
219
3
                            return Ok(Handshake::Healthy(HealthyHandshake {
220
3
                                state: NegotiationState::Encryption { handshake: updated },
221
3
                            }));
222
                        }
223
                    };
224
                }
225
226
                NegotiationState::Multiplexing {
227
5
                    negotiation,
228
5
                    mut encryption,
229
5
                    peer_id,
230
5
                } => {
231
5
                    // During the multiplexing protocol negotiation, all exchanges have to go
232
5
                    // through the Noise cipher.
233
5
234
5
                    if read_write.expected_incoming_bytes.is_none() {
235
0
                        return Err(HandshakeError::MultiplexingMultistreamSelect(
236
0
                            multistream_select::Error::ReadClosed,
237
0
                        ));
238
5
                    }
239
5
                    if read_write.write_bytes_queueable.is_none() {
240
0
                        return Err(HandshakeError::MultiplexingMultistreamSelect(
241
0
                            multistream_select::Error::WriteClosed,
242
0
                        ));
243
5
                    }
244
245
5
                    let negotiation_update = {
246
5
                        let mut decrypted_stream = encryption
247
5
                            .read_write(read_write)
248
5
                            .map_err(HandshakeError::Noise)
?0
;
249
5
                        negotiation
250
5
                            .read_write(&mut *decrypted_stream)
251
5
                            .map_err(HandshakeError::MultiplexingMultistreamSelect)
?0
252
                    };
253
254
5
                    return match negotiation_update {
255
2
                        multistream_select::Negotiation::InProgress(updated) => {
256
2
                            Ok(Handshake::Healthy(HealthyHandshake {
257
2
                                state: NegotiationState::Multiplexing {
258
2
                                    negotiation: updated,
259
2
                                    encryption,
260
2
                                    peer_id,
261
2
                                },
262
2
                            }))
263
                        }
264
1
                        multistream_select::Negotiation::ListenerAcceptOrDeny(accept_reject) => {
265
1
                            let negotiation =
266
1
                                if accept_reject.requested_protocol() == yamux::PROTOCOL_NAME {
267
1
                                    accept_reject.accept()
268
                                } else {
269
0
                                    accept_reject.reject()
270
                                };
271
1
                            self.state = NegotiationState::Multiplexing {
272
1
                                peer_id,
273
1
                                encryption,
274
1
                                negotiation,
275
1
                            };
276
1
                            continue;
277
                        }
278
2
                        multistream_select::Negotiation::Success => Ok(Handshake::Success {
279
2
                            connection: ConnectionPrototype::from_noise_yamux(*encryption),
280
2
                            remote_peer_id: peer_id,
281
2
                        }),
282
                        multistream_select::Negotiation::NotAvailable => {
283
0
                            Err(HandshakeError::NoMultiplexingProtocol)
284
                        }
285
                    };
286
                }
287
            }
288
        }
289
8
    }
Unexecuted instantiation: _RINvMs_NtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection23single_stream_handshakeNtB5_16HealthyHandshake10read_writeNtNtCsaYZPK01V26L_4core4time8DurationECsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RINvMs_NtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection23single_stream_handshakeNtB5_16HealthyHandshake10read_writepEBb_
Unexecuted instantiation: _RINvMs_NtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection23single_stream_handshakeNtB5_16HealthyHandshake10read_writeNtNtCsbpXXxgr6u8g_3std4time7InstantECsiUjFBJteJ7x_17smoldot_full_node
290
}
291
292
impl fmt::Debug for HealthyHandshake {
293
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
294
0
        f.debug_struct("HealthyHandshake").finish()
295
0
    }
Unexecuted instantiation: _RNvXs0_NtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection23single_stream_handshakeNtB5_16HealthyHandshakeNtNtCsaYZPK01V26L_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXs0_NtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection23single_stream_handshakeNtB5_16HealthyHandshakeNtNtCsaYZPK01V26L_4core3fmt5Debug3fmt
296
}
297
298
/// Error during a connection handshake. The connection should be shut down.
299
0
#[derive(Debug, derive_more::Display)]
Unexecuted instantiation: _RNvXs5_NtNtNtCsN16ciHI6Qf_7smoldot6libp2p10connection23single_stream_handshakeNtB5_14HandshakeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXs5_NtNtNtCseuYC0Zibziv_7smoldot6libp2p10connection23single_stream_handshakeNtB5_14HandshakeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
300
pub enum HandshakeError {
301
    /// Protocol error during the multistream-select negotiation of the encryption protocol.
302
    #[display(fmt = "Encryption protocol selection error: {_0}")]
303
    EncryptionMultistreamSelect(multistream_select::Error),
304
    /// Protocol error during the multistream-select negotiation of the multiplexing protocol.
305
    #[display(fmt = "Multiplexing protocol selection error: {_0}")]
306
    MultiplexingMultistreamSelect(multistream_select::Error),
307
    /// Protocol error during the noise handshake.
308
    #[display(fmt = "Noise handshake error: {_0}")]
309
    NoiseHandshake(noise::HandshakeError),
310
    /// No encryption protocol in common with the remote.
311
    ///
312
    /// The remote is behaving correctly but isn't compatible with the local node.
313
    NoEncryptionProtocol,
314
    /// No multiplexing protocol in common with the remote.
315
    ///
316
    /// The remote is behaving correctly but isn't compatible with the local node.
317
    NoMultiplexingProtocol,
318
    /// Error in the noise cipher. Data has most likely been corrupted.
319
    #[display(fmt = "Noise cipher error: {_0}")]
320
    Noise(noise::CipherError),
321
}