I have created 4 functions doing similar stuff, however parse_udp enforced me to use the lifetime while previous calls didn't.
But finally parse_dhcp isn't working because "returns a value referencing data owned by the current function"
Please explain me the differences...
fn parse_ethernet(payload: &[u8])
-> Result<(&[u8], EthernetRepr), PacketParseError> {
let eth_frame =
EthernetFrame::new_checked(payload)
.map_err(PacketParseError::EthernetError)?;
let eth_repr =
EthernetRepr::parse(ð_frame)
.map_err(PacketParseError::EthernetError)?;
Ok((eth_frame.payload(), eth_repr))
}
fn parse_ipv4(payload: &[u8])
-> Result<(&[u8], Ipv4Repr), PacketParseError> {
let ipv4_packet =
Ipv4Packet::new_checked(payload)
.map_err(|e| PacketParseError::Ipv4PacketError(e))?;
let ipv4_repr =
Ipv4Repr::parse(&ipv4_packet, &ChecksumCapabilities::ignored())
.map_err(PacketParseError::Ipv4ReprParseError)?; // shorthand for |e| PacketParseError::Ipv4ReprParseError(e)
Ok((ipv4_packet.payload(), ipv4_repr))
}
fn parse_udp<'a>(payload: &'a [u8], ipv4_repr: &Ipv4Repr)
-> Result<(&'a [u8], UdpRepr), PacketParseError> {
let udp_packet =
UdpPacket::new_checked(payload)
.map_err(PacketParseError::UdpPacketError)?;
let udp_repr =
UdpRepr::parse(
&udp_packet,
&IpAddress::from(ipv4_repr.src_addr), // Convert Ipv4Address to IpAddress
&IpAddress::from(ipv4_repr.dst_addr), // Convert Ipv4Address to IpAddress
&ChecksumCapabilities::ignored())
.map_err(PacketParseError::UdpReprParseError)?;
Ok((udp_packet.payload(), udp_repr))
}
fn parse_dhcp(payload: &[u8])
-> Result<DhcpRepr, PacketParseError> {
let dhcp_packet =
DhcpPacket::new_checked(payload)
.map_err(PacketParseError::DhcpPacketError)?;
let dhcp_repr =
DhcpRepr::parse(&dhcp_packet)
.map_err(PacketParseError::DhcpReprParseError)?;
Ok(dhcp_repr) // this gives an error :: returns a value referencing data owned by the current function
}
Please post the signature of DhcpRepr::parse. If the lifetime of the input param reference is also the lifetime of the return value, that would explain the error.
Also, be sure to always post full errors -- the error from running cargo check or cargo build in the terminal, if your IDE is not giving you the full error. It often has details and hints that help in diagnosing the problem.
The DhcpRepr borrows the DhcpPacket (not just the data it borrows). Therefore, you cannot return a DhcpRepr from a function that doesn't take a DhcpPacket as input.
This (perhaps inconveniently) means you have to keep around the packet variable for as long as you're accessing the repr variable since the latter borrows from the former. And you can't store them in the same struct since that would be a self-referential struct, which is not supported in Rust.
You could convert those fields to something owned (e.g. Option<Vec<u8>> for the parameter_request_list) and return that as well, if you need the data. You'd have to reconstruct the DhcpRepr fields elsewhere probably.
Edit: You can actually return DhcpRepr<'static> with this approach, since you're not borrowing anything in DhcpRepr anymore (but then it may be a breaking change to go back to being borrowing if upstream improves in the way discussed below).
Better solutions are only possible by changing upstream. I believe they could improve things in a non-breaking manner by adding some method like: