First of all, I know that a minimim reproducible example is recommended. I really tried making one but I couldn't. Since I dont have idea of where this error comes from, I couldn't make a minimum reproducible example that has the same error. They all compile ok.
So I ask of you guys a little patience with someone that just arrived in Rust. I've truly read everything from the rust lang tutorials about lifetime but this question makes no sense at all for me. You'll also be helping someone in an open source problem.
Take a look:
pub struct Item<'a, 'b: 'a> {
socket: Socket<'a, 'b>,
refs: usize
}
#[derive(Debug)]
pub struct Set<'a, 'b: 'a, 'c: 'a + 'b> {
sockets: ManagedSlice<'a, Option<Item<'b, 'c>>>
}
pub struct TunSmolStack<'a, 'b, 'c> {
sockets: SocketSet<'a, 'b, 'c >,
}
impl<'a, 'b, 'c> TunSmolStack<'a, 'b, 'c> {
pub fn new(interface_name: String) -> Result<TunSmolStack<'a, 'b, 'c>, u32> {
let device = TunDevice::new("tun").unwrap();
let neighbor_cache = NeighborCache::new(BTreeMap::new());
let socket_set = SocketSet::new(vec![]);
let mut interface = InterfaceBuilder::new(device)
.neighbor_cache(neighbor_cache)
.finalize();
Ok(TunSmolStack {
sockets: socket_set,
})
}
pub fn add_socket(&mut self, socket_type: SocketType) -> usize {
match socket_type {
SocketType::TCP => {
let rx_buffer = TcpSocketBuffer::new(vec![0; 1024]);
let tx_buffer = TcpSocketBuffer::new(vec![0; 1024]);
let socket = TcpSocket::new(rx_buffer, tx_buffer);
self.sockets.add(socket);
}
My problem is in the self.sockets.add(socket);
, but let's see the two structures that are missing:
TcpSocketBuffer
is just another name for RingBuffer
:
#[derive(Debug)]
pub struct RingBuffer<'a, T: 'a> {
storage: ManagedSlice<'a, T>,
read_at: usize,
length: usize,
}
pub fn new<S>(storage: S) -> RingBuffer<'a, T>
where S: Into<ManagedSlice<'a, T>>,
{
RingBuffer {
storage: storage.into(),
read_at: 0,
length: 0,
}
}
And here's the TcpSocket's new method:
impl<'a> TcpSocket<'a> {
#[allow(unused_comparisons)] // small usize platforms always pass rx_capacity check
/// Create a socket using the given buffers.
pub fn new<T>(rx_buffer: T, tx_buffer: T) -> TcpSocket<'a>
where T: Into<SocketBuffer<'a>> {
let (rx_buffer, tx_buffer) = (rx_buffer.into(), tx_buffer.into());
let rx_capacity = rx_buffer.capacity();
// From RFC 1323:
// [...] the above constraints imply that 2 * the max window size must be less
// than 2**31 [...] Thus, the shift count must be limited to 14 (which allows
// windows of 2**30 = 1 Gbyte).
if rx_capacity > (1 << 30) {
panic!("receiving buffer too large, cannot exceed 1 GiB")
}
let rx_cap_log2 = mem::size_of::<usize>() * 8 -
rx_capacity.leading_zeros() as usize;
TcpSocket {
meta: SocketMeta::default(),
state: State::Closed,
timer: Timer::default(),
assembler: Assembler::new(rx_buffer.capacity()),
tx_buffer: tx_buffer,
rx_buffer: rx_buffer,
timeout: None,
keep_alive: None,
hop_limit: None,
listen_address: IpAddress::default(),
local_endpoint: IpEndpoint::default(),
remote_endpoint: IpEndpoint::default(),
local_seq_no: TcpSeqNumber::default(),
remote_seq_no: TcpSeqNumber::default(),
remote_last_seq: TcpSeqNumber::default(),
remote_last_ack: None,
remote_last_win: 0,
remote_win_len: 0,
remote_win_shift: rx_cap_log2.saturating_sub(16) as u8,
remote_win_scale: None,
remote_has_sack: false,
remote_mss: DEFAULT_MSS,
remote_last_ts: None,
local_rx_last_ack: None,
local_rx_last_seq: None,
local_rx_dup_acks: 0,
}
}
The error is on this line:
self.sockets.add(socket);
Error:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements
--> src/virtual_tun/smol_stack.rs:51:30
|
51 | self.sockets.add(socket);
| ^^^
|
note: first, the lifetime cannot outlive the lifetime `'b` as defined on the impl at 23:10...
--> src/virtual_tun/smol_stack.rs:23:10
|
23 | impl<'a, 'b, 'c> TunSmolStack<'a, 'b, 'c> {
| ^^
note: ...but the lifetime must also be valid for the lifetime `'c` as defined on the impl at 23:14...
--> src/virtual_tun/smol_stack.rs:23:14
|
23 | impl<'a, 'b, 'c> TunSmolStack<'a, 'b, 'c> {
| ^^
note: ...so that the types are compatible
--> src/virtual_tun/smol_stack.rs:51:30
|
51 | self.sockets.add(socket);
| ^^^
= note: expected `&mut virtual_tun::smoltcp::socket::SocketSet<'_, '_, '_>`
found `&mut virtual_tun::smoltcp::socket::SocketSet<'a, 'b, 'c>`
At first, it looks like a simple ownership problem. Let's see it with the lines before, that have the same scope as the new method:
let rx_buffer = TcpSocketBuffer::new(vec![0; 1024]);
let tx_buffer = TcpSocketBuffer::new(vec![0; 1024]);
let socket = TcpSocket::new(rx_buffer, tx_buffer);
self.sockets.add(socket);
since sockets
lives in self
, and I'm trying to add socket
from a scope that is gonna be out soon (scope of the new
method), this looks like a problem of adding something that is going to be invalid soon.
However, both TcpSocketBuffer::new
and TcpSocket::new
take its unique parameter by moving it (owning it), not by borrowing it. More than that: both new
methods transform its inputs into a ManagedSlice
. If we look on the From
method on ManagedSlice
for a vector std::vec
, it owns the vector: rust-managed/slice.rs at bb952078405f436ffd53925a19f50ab4abd9d397 Ā· smoltcp-rs/rust-managed Ā· GitHub so again, no references are being used! So there should be no lifetime problem at all. References aren't being used! Both rx_buffer, tx_buffer
go inside socket
being moved, and socket
goes into self.sockets
by being moved. And these 3 objects transform their inputs into ManagedSlice
s that also move the vector, not borrow a reference to it.
Here's the full code if someone want to give a better read: https://github.com/lucaszanella/smoltcp_openvpn_bridge/blob/ea2ab0670436aab3de3b4742cc9cb089ef7c06ff/src/virtual_tun/smol_stack.rs