Skip to content

Commit 556447c

Browse files
authored
Make use of NLL to clean up handshaking logic (#576)
1 parent 7de2ccc commit 556447c

File tree

2 files changed

+86
-94
lines changed

2 files changed

+86
-94
lines changed

.github/workflows/CI.yml

+29
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,32 @@ jobs:
8383
- name: Check minimal versions
8484
run: cargo clean; cargo update -Zminimal-versions; cargo check
8585
if: matrix.rust == 'nightly'
86+
87+
msrv:
88+
name: Check MSRV (${{ matrix.rust }})
89+
needs: [style]
90+
strategy:
91+
matrix:
92+
rust:
93+
- 1.46 # never go past Hyper's own MSRV
94+
95+
os:
96+
- ubuntu-latest
97+
98+
runs-on: ${{ matrix.os }}
99+
100+
steps:
101+
- name: Checkout
102+
uses: actions/checkout@v1
103+
104+
- name: Install Rust (${{ matrix.rust }})
105+
uses: actions-rs/toolchain@v1
106+
with:
107+
profile: minimal
108+
toolchain: ${{ matrix.rust }}
109+
override: true
110+
111+
- name: Check
112+
uses: actions-rs/cargo@v1
113+
with:
114+
command: check

src/server.rs

+57-94
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ use std::future::Future;
126126
use std::pin::Pin;
127127
use std::task::{Context, Poll};
128128
use std::time::Duration;
129-
use std::{convert, fmt, io, mem};
129+
use std::{fmt, io};
130130
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
131131
use tracing::instrument::{Instrument, Instrumented};
132132

@@ -301,8 +301,8 @@ enum Handshaking<T, B: Buf> {
301301
Flushing(Instrumented<Flush<T, Prioritized<B>>>),
302302
/// State 2. Connection is waiting for the client preface.
303303
ReadingPreface(Instrumented<ReadPreface<T, Prioritized<B>>>),
304-
/// Dummy state for `mem::replace`.
305-
Empty,
304+
/// State 3. Handshake is done, polling again would panic.
305+
Done,
306306
}
307307

308308
/// Flush a Sink
@@ -387,7 +387,8 @@ where
387387
.expect("invalid SETTINGS frame");
388388

389389
// Create the handshake future.
390-
let state = Handshaking::from(codec);
390+
let state =
391+
Handshaking::Flushing(Flush::new(codec).instrument(tracing::trace_span!("flush")));
391392

392393
drop(entered);
393394

@@ -1269,63 +1270,58 @@ where
12691270
let span = self.span.clone(); // XXX(eliza): T_T
12701271
let _e = span.enter();
12711272
tracing::trace!(state = ?self.state);
1272-
use crate::server::Handshaking::*;
1273-
1274-
self.state = if let Flushing(ref mut flush) = self.state {
1275-
// We're currently flushing a pending SETTINGS frame. Poll the
1276-
// flush future, and, if it's completed, advance our state to wait
1277-
// for the client preface.
1278-
let codec = match Pin::new(flush).poll(cx)? {
1279-
Poll::Pending => {
1280-
tracing::trace!(flush.poll = %"Pending");
1281-
return Poll::Pending;
1273+
1274+
loop {
1275+
match &mut self.state {
1276+
Handshaking::Flushing(flush) => {
1277+
// We're currently flushing a pending SETTINGS frame. Poll the
1278+
// flush future, and, if it's completed, advance our state to wait
1279+
// for the client preface.
1280+
let codec = match Pin::new(flush).poll(cx)? {
1281+
Poll::Pending => {
1282+
tracing::trace!(flush.poll = %"Pending");
1283+
return Poll::Pending;
1284+
}
1285+
Poll::Ready(flushed) => {
1286+
tracing::trace!(flush.poll = %"Ready");
1287+
flushed
1288+
}
1289+
};
1290+
self.state = Handshaking::ReadingPreface(
1291+
ReadPreface::new(codec).instrument(tracing::trace_span!("read_preface")),
1292+
);
12821293
}
1283-
Poll::Ready(flushed) => {
1284-
tracing::trace!(flush.poll = %"Ready");
1285-
flushed
1294+
Handshaking::ReadingPreface(read) => {
1295+
let codec = ready!(Pin::new(read).poll(cx)?);
1296+
1297+
self.state = Handshaking::Done;
1298+
1299+
let connection = proto::Connection::new(
1300+
codec,
1301+
Config {
1302+
next_stream_id: 2.into(),
1303+
// Server does not need to locally initiate any streams
1304+
initial_max_send_streams: 0,
1305+
max_send_buffer_size: self.builder.max_send_buffer_size,
1306+
reset_stream_duration: self.builder.reset_stream_duration,
1307+
reset_stream_max: self.builder.reset_stream_max,
1308+
settings: self.builder.settings.clone(),
1309+
},
1310+
);
1311+
1312+
tracing::trace!("connection established!");
1313+
let mut c = Connection { connection };
1314+
if let Some(sz) = self.builder.initial_target_connection_window_size {
1315+
c.set_target_window_size(sz);
1316+
}
1317+
1318+
return Poll::Ready(Ok(c));
1319+
}
1320+
Handshaking::Done => {
1321+
panic!("Handshaking::poll() called again after handshaking was complete")
12861322
}
1287-
};
1288-
Handshaking::from(ReadPreface::new(codec))
1289-
} else {
1290-
// Otherwise, we haven't actually advanced the state, but we have
1291-
// to replace it with itself, because we have to return a value.
1292-
// (note that the assignment to `self.state` has to be outside of
1293-
// the `if let` block above in order to placate the borrow checker).
1294-
mem::replace(&mut self.state, Handshaking::Empty)
1295-
};
1296-
let poll = if let ReadingPreface(ref mut read) = self.state {
1297-
// We're now waiting for the client preface. Poll the `ReadPreface`
1298-
// future. If it has completed, we will create a `Connection` handle
1299-
// for the connection.
1300-
Pin::new(read).poll(cx)
1301-
// Actually creating the `Connection` has to occur outside of this
1302-
// `if let` block, because we've borrowed `self` mutably in order
1303-
// to poll the state and won't be able to borrow the SETTINGS frame
1304-
// as well until we release the borrow for `poll()`.
1305-
} else {
1306-
unreachable!("Handshake::poll() state was not advanced completely!")
1307-
};
1308-
poll?.map(|codec| {
1309-
let connection = proto::Connection::new(
1310-
codec,
1311-
Config {
1312-
next_stream_id: 2.into(),
1313-
// Server does not need to locally initiate any streams
1314-
initial_max_send_streams: 0,
1315-
max_send_buffer_size: self.builder.max_send_buffer_size,
1316-
reset_stream_duration: self.builder.reset_stream_duration,
1317-
reset_stream_max: self.builder.reset_stream_max,
1318-
settings: self.builder.settings.clone(),
1319-
},
1320-
);
1321-
1322-
tracing::trace!("connection established!");
1323-
let mut c = Connection { connection };
1324-
if let Some(sz) = self.builder.initial_target_connection_window_size {
1325-
c.set_target_window_size(sz);
13261323
}
1327-
Ok(c)
1328-
})
1324+
}
13291325
}
13301326
}
13311327

@@ -1548,42 +1544,9 @@ where
15481544
#[inline]
15491545
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
15501546
match *self {
1551-
Handshaking::Flushing(_) => write!(f, "Handshaking::Flushing(_)"),
1552-
Handshaking::ReadingPreface(_) => write!(f, "Handshaking::ReadingPreface(_)"),
1553-
Handshaking::Empty => write!(f, "Handshaking::Empty"),
1547+
Handshaking::Flushing(_) => f.write_str("Flushing(_)"),
1548+
Handshaking::ReadingPreface(_) => f.write_str("ReadingPreface(_)"),
1549+
Handshaking::Done => f.write_str("Done"),
15541550
}
15551551
}
15561552
}
1557-
1558-
impl<T, B> convert::From<Flush<T, Prioritized<B>>> for Handshaking<T, B>
1559-
where
1560-
T: AsyncRead + AsyncWrite,
1561-
B: Buf,
1562-
{
1563-
#[inline]
1564-
fn from(flush: Flush<T, Prioritized<B>>) -> Self {
1565-
Handshaking::Flushing(flush.instrument(tracing::trace_span!("flush")))
1566-
}
1567-
}
1568-
1569-
impl<T, B> convert::From<ReadPreface<T, Prioritized<B>>> for Handshaking<T, B>
1570-
where
1571-
T: AsyncRead + AsyncWrite,
1572-
B: Buf,
1573-
{
1574-
#[inline]
1575-
fn from(read: ReadPreface<T, Prioritized<B>>) -> Self {
1576-
Handshaking::ReadingPreface(read.instrument(tracing::trace_span!("read_preface")))
1577-
}
1578-
}
1579-
1580-
impl<T, B> convert::From<Codec<T, Prioritized<B>>> for Handshaking<T, B>
1581-
where
1582-
T: AsyncRead + AsyncWrite,
1583-
B: Buf,
1584-
{
1585-
#[inline]
1586-
fn from(codec: Codec<T, Prioritized<B>>) -> Self {
1587-
Handshaking::from(Flush::new(codec))
1588-
}
1589-
}

0 commit comments

Comments
 (0)