Implement the TCP SYN-SENT state.

This commit is contained in:
whitequark 2017-03-05 03:52:47 +00:00
parent e36e05905c
commit cd894460f5
2 changed files with 151 additions and 8 deletions

View File

@ -25,6 +25,11 @@ impl<'a> SocketBuffer<'a> {
} }
} }
fn clear(&mut self) {
self.read_at = 0;
self.length = 0;
}
fn capacity(&self) -> usize { fn capacity(&self) -> usize {
self.storage.len() self.storage.len()
} }
@ -253,6 +258,8 @@ pub struct TcpSocket<'a> {
debug_id: usize debug_id: usize
} }
const DEFAULT_MSS: usize = 536;
impl<'a> TcpSocket<'a> { impl<'a> TcpSocket<'a> {
/// Create a socket using the given buffers. /// Create a socket using the given buffers.
pub fn new<T>(rx_buffer: T, tx_buffer: T) -> Socket<'a, 'static> pub fn new<T>(rx_buffer: T, tx_buffer: T) -> Socket<'a, 'static>
@ -273,7 +280,7 @@ impl<'a> TcpSocket<'a> {
remote_last_seq: TcpSeqNumber(0), remote_last_seq: TcpSeqNumber(0),
remote_last_ack: TcpSeqNumber(0), remote_last_ack: TcpSeqNumber(0),
remote_win_len: 0, remote_win_len: 0,
remote_mss: 536, remote_mss: DEFAULT_MSS,
retransmit: Retransmit::new(), retransmit: Retransmit::new(),
tx_buffer: tx_buffer.into(), tx_buffer: tx_buffer.into(),
rx_buffer: rx_buffer.into(), rx_buffer: rx_buffer.into(),
@ -311,20 +318,77 @@ impl<'a> TcpSocket<'a> {
self.state self.state
} }
fn reset(&mut self) {
self.listen_address = IpAddress::default();
self.local_endpoint = IpEndpoint::default();
self.remote_endpoint = IpEndpoint::default();
self.local_seq_no = TcpSeqNumber(0);
self.remote_seq_no = TcpSeqNumber(0);
self.remote_last_seq = TcpSeqNumber(0);
self.remote_last_ack = TcpSeqNumber(0);
self.remote_win_len = 0;
self.remote_win_len = 0;
self.remote_mss = DEFAULT_MSS;
self.retransmit.reset();
self.tx_buffer.clear();
self.rx_buffer.clear();
}
/// Start listening on the given endpoint. /// Start listening on the given endpoint.
/// ///
/// This function returns an error if the socket was open; see [is_open](#method.is_open). /// This function returns an error if the socket was open; see [is_open](#method.is_open).
pub fn listen<T: Into<IpEndpoint>>(&mut self, endpoint: T) -> Result<(), ()> { /// It also returns an error if the specified port is zero.
if self.is_open() { return Err(()) } pub fn listen<T>(&mut self, local_endpoint: T) -> Result<(), ()>
where T: Into<IpEndpoint> {
let local_endpoint = local_endpoint.into();
let endpoint = endpoint.into(); if self.is_open() { return Err(()) }
self.listen_address = endpoint.addr; if local_endpoint.port == 0 { return Err(()) }
self.local_endpoint = endpoint;
self.reset();
self.listen_address = local_endpoint.addr;
self.local_endpoint = local_endpoint;
self.remote_endpoint = IpEndpoint::default(); self.remote_endpoint = IpEndpoint::default();
self.set_state(State::Listen); self.set_state(State::Listen);
Ok(()) Ok(())
} }
/// Connect to a given endpoint.
///
/// The local port must be provided explicitly. Assuming `fn get_ephemeral_port() -> u16`
/// allocates a port from the 49152 to 65535 range, a connection may be established as follows:
///
/// ```rust,ignore
/// socket.connect((IpAddress::v4(10, 0, 0, 1), 80), get_ephemeral_port())
/// ```
///
/// The local address may optionally be provided.
///
/// This function returns an error if the socket was open; see [is_open](#method.is_open).
/// It also returns an error if the local or remote port is zero, or if
/// the local or remote address is unspecified.
pub fn connect<T, U>(&mut self, remote_endpoint: T, local_endpoint: U) -> Result<(), ()>
where T: Into<IpEndpoint>, U: Into<IpEndpoint> {
let remote_endpoint = remote_endpoint.into();
let local_endpoint = local_endpoint.into();
if self.is_open() { return Err(()) }
if remote_endpoint.port == 0 { return Err(()) }
if remote_endpoint.addr.is_unspecified() { return Err(()) }
if local_endpoint.port == 0 { return Err(()) }
if local_endpoint.addr.is_unspecified() { return Err(()) }
// Carry over the local sequence number.
let local_seq_no = self.local_seq_no;
self.reset();
self.local_endpoint = local_endpoint;
self.remote_endpoint = remote_endpoint;
self.local_seq_no = local_seq_no;
self.set_state(State::SynSent);
Ok(())
}
/// Close the transmit half of the full-duplex connection. /// Close the transmit half of the full-duplex connection.
/// ///
/// Note that there is no corresponding function for the receive half of the full-duplex /// Note that there is no corresponding function for the receive half of the full-duplex
@ -715,6 +779,23 @@ impl<'a> TcpSocket<'a> {
self.retransmit.reset(); self.retransmit.reset();
} }
// SYN|ACK packets in the SYN-SENT state change it to ESTABLISHED.
(State::SynSent, TcpRepr {
control: TcpControl::Syn, seq_number, ack_number: Some(_),
max_seg_size, ..
}) => {
net_trace!("[{}]{}:{}: received SYN|ACK",
self.debug_id, self.local_endpoint, self.remote_endpoint);
self.remote_last_seq = self.local_seq_no + 1;
self.remote_seq_no = seq_number + 1;
self.remote_last_ack = seq_number;
if let Some(max_seg_size) = max_seg_size {
self.remote_mss = max_seg_size as usize;
}
self.set_state(State::Established);
self.retransmit.reset();
}
// ACK packets in ESTABLISHED state reset the retransmit timer. // ACK packets in ESTABLISHED state reset the retransmit timer.
(State::Established, TcpRepr { control: TcpControl::None, .. }) => { (State::Established, TcpRepr { control: TcpControl::None, .. }) => {
self.retransmit.reset() self.retransmit.reset()
@ -962,8 +1043,10 @@ impl<'a> TcpSocket<'a> {
self.retransmit.delay); self.retransmit.delay);
} }
repr.ack_number = Some(ack_number); if self.state != State::SynSent {
self.remote_last_ack = ack_number; repr.ack_number = Some(ack_number);
self.remote_last_ack = ack_number;
}
// Remember the header length before enabling the MSS option, since that option // Remember the header length before enabling the MSS option, since that option
// only affects SYN packets. // only affects SYN packets.
@ -1249,6 +1332,12 @@ mod test {
sanity!(s, socket_listen()); sanity!(s, socket_listen());
} }
#[test]
fn test_listen_validation() {
let mut s = socket();
assert_eq!(s.listen(0), Err(()));
}
#[test] #[test]
fn test_listen_syn() { fn test_listen_syn() {
let mut s = socket_listen(); let mut s = socket_listen();
@ -1358,6 +1447,54 @@ mod test {
s s
} }
#[test]
fn test_connect_validation() {
let mut s = socket();
assert_eq!(s.connect(REMOTE_END, (IpAddress::Unspecified, 80)), Err(()));
assert_eq!(s.connect(REMOTE_END, (IpAddress::v4(0, 0, 0, 0), 80)), Err(()));
assert_eq!(s.connect(REMOTE_END, (IpAddress::v4(10, 0, 0, 0), 0)), Err(()));
assert_eq!(s.connect((IpAddress::Unspecified, 80), LOCAL_END), Err(()));
assert_eq!(s.connect((IpAddress::v4(0, 0, 0, 0), 80), LOCAL_END), Err(()));
assert_eq!(s.connect((IpAddress::v4(10, 0, 0, 0), 0), LOCAL_END), Err(()));
}
#[test]
fn test_syn_sent_sanity() {
let mut s = socket();
s.local_seq_no = LOCAL_SEQ;
s.connect(REMOTE_END, LOCAL_END).unwrap();
sanity!(s, socket_syn_sent());
}
#[test]
fn test_syn_sent_syn_ack() {
let mut s = socket_syn_sent();
recv!(s, [TcpRepr {
control: TcpControl::Syn,
seq_number: LOCAL_SEQ,
ack_number: None,
max_seg_size: Some(1480),
..RECV_TEMPL
}]);
send!(s, TcpRepr {
control: TcpControl::Syn,
seq_number: REMOTE_SEQ,
ack_number: Some(LOCAL_SEQ + 1),
max_seg_size: Some(1400),
..SEND_TEMPL
});
recv!(s, [TcpRepr {
seq_number: LOCAL_SEQ + 1,
ack_number: Some(REMOTE_SEQ + 1),
..RECV_TEMPL
}]);
assert_eq!(s.state, State::Established);
sanity!(s, TcpSocket {
retransmit: Retransmit { resend_at: 100, delay: 100 },
..socket_established()
});
}
#[test] #[test]
fn test_syn_sent_rst() { fn test_syn_sent_rst() {
let mut s = socket_syn_sent(); let mut s = socket_syn_sent();

View File

@ -112,6 +112,12 @@ impl From<u16> for Endpoint {
} }
} }
impl<T: Into<Address>> From<(T, u16)> for Endpoint {
fn from((addr, port): (T, u16)) -> Endpoint {
Endpoint { addr: addr.into(), port: port }
}
}
/// An IP packet representation. /// An IP packet representation.
/// ///
/// This enum abstracts the various versions of IP packets. It either contains a concrete /// This enum abstracts the various versions of IP packets. It either contains a concrete