Fix determination of local address from incoming packets.

We've advertised this capability before in examples, but it did not
actually work.
This commit is contained in:
whitequark 2017-07-23 23:07:55 +00:00
parent bcd9be3d17
commit 1c41f2d7fa
3 changed files with 48 additions and 6 deletions

View File

@ -149,7 +149,7 @@ fn main() {
if !socket.is_open() {
if !did_connect {
socket.connect((IpAddress::v4(127, 0, 0, 1), 1234),
(IpAddress::v4(127, 0, 0, 1), 65000)).unwrap();
(IpAddress::Unspecified, 65000)).unwrap();
did_connect = true;
}
}

View File

@ -368,7 +368,7 @@ impl<'a> TcpSocket<'a> {
/// 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:
/// allocates a port between 49152 and 65535, a connection may be established as follows:
///
/// ```rust,ignore
/// socket.connect((IpAddress::v4(10, 0, 0, 1), 80), get_ephemeral_port())
@ -386,9 +386,16 @@ impl<'a> TcpSocket<'a> {
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(()) }
// If local address is not provided, use an unspecified address but a specified protocol.
// This lets us lower IpRepr later to determine IP header size and calculate MSS,
// but without committing to a specific address right away.
let local_addr = match remote_endpoint.addr {
IpAddress::Unspecified => return Err(()),
_ => remote_endpoint.addr.as_unspecified(),
};
let local_endpoint = IpEndpoint { addr: local_addr, ..local_endpoint };
// Carry over the local sequence number.
let local_seq_no = self.local_seq_no;
@ -852,6 +859,7 @@ impl<'a> TcpSocket<'a> {
}) => {
net_trace!("[{}]{}:{}: received SYN|ACK",
self.debug_id, self.local_endpoint, self.remote_endpoint);
self.local_endpoint = IpEndpoint::new(ip_repr.dst_addr(), repr.dst_port);
self.remote_last_seq = self.local_seq_no + 1;
self.remote_seq_no = seq_number + 1;
self.remote_last_ack = seq_number;
@ -1269,6 +1277,8 @@ mod test {
let mut limits = DeviceLimits::default();
limits.max_transmission_unit = 1520;
let result = socket.dispatch(timestamp, &limits, &mut |ip_repr, payload| {
let ip_repr = ip_repr.lower(&[LOCAL_END.addr.into()]).unwrap();
assert_eq!(ip_repr.protocol(), IpProtocol::Tcp);
assert_eq!(ip_repr.src_addr(), LOCAL_IP);
assert_eq!(ip_repr.dst_addr(), REMOTE_IP);
@ -1533,7 +1543,7 @@ mod test {
fn socket_syn_sent() -> TcpSocket<'static> {
let mut s = socket();
s.state = State::SynSent;
s.local_endpoint = LOCAL_END;
s.local_endpoint = IpEndpoint::new(IpAddress::v4(0, 0, 0, 0), LOCAL_PORT);
s.remote_endpoint = REMOTE_END;
s.local_seq_no = LOCAL_SEQ;
s
@ -1542,7 +1552,7 @@ mod test {
#[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::Unspecified, 80)), Ok(()));
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(()));
@ -1550,6 +1560,29 @@ mod test {
assert_eq!(s.connect((IpAddress::v4(10, 0, 0, 0), 0), LOCAL_END), Err(()));
}
#[test]
fn test_connect() {
let mut s = socket();
s.local_seq_no = LOCAL_SEQ;
s.connect(REMOTE_END, LOCAL_END.port).unwrap();
assert_eq!(s.local_endpoint, IpEndpoint::new(IpAddress::v4(0, 0, 0, 0), LOCAL_END.port));
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
});
assert_eq!(s.local_endpoint, LOCAL_END);
}
#[test]
fn test_syn_sent_sanity() {
let mut s = socket();

View File

@ -71,6 +71,15 @@ impl Address {
&Address::Ipv4(addr) => addr.is_unspecified()
}
}
/// Return an unspecified address that has the same IP version as `self`.
pub fn as_unspecified(&self) -> Address {
match self {
&Address::Unspecified => Address::Unspecified,
// &Address::Ipv4 => Address::Ipv4(Ipv4Address::UNSPECIFIED),
&Address::Ipv4(_) => Address::Ipv4(Ipv4Address(/*FIXME*/[0x00; 4])),
}
}
}
impl Default for Address {