This paves way for adding more metadata apart from handles,
such as caches and so on.
This commit also removes SocketHandle::EMPTY in favor of
SocketHandle::default() since they are functionally identical.
- Add the ttl member to the IpRepr
- Add the ttl member along with setters and getters to the tcp and udp
socket types
- Add unit tests for the new set_ttl parameter
- Update usage of IpRepr to include the ttl value
This is basically a rename that now calls an apple an apple,
except user code can no longer change it. It's not obvious if
user code getting the socket handle from the socket is very useful,
but it's not harmful either, so why not.
The previous implementation made no sense. It is obvious that
poll_at() should use the same mechanisms to decide whether dispatch()
should be called as dispatch() itself uses to decide whether to send
anything.
This fixes numerous busy looping issues that arise if the return
value of poll() is used for waiting.
1. Apart from non-empty transmit buffer, a state which transmits
a FIN flag should also be considerd. Otherwise, closing a socket
with an empty transmit buffer may retransmit the FIN flag forever.
2. Timeout poll requests should only be overridden by timer poll
requests when the latter is earlier.
After this change, if an 1s timeout is set on a socket that received
no packet for 2s, it will be instantly aborted, which seems
more reasonable. Also, this makes the `self.remote_last_ts.is_none()`
branch in TcpSocket::dispatch() actually behave as described.
This also makes TcpSocket::{send,recv}_slice slightly more efficient
in case when the slice wraps around the corresponding buffer,
halving the necessary amount of calls.
This is prohibited by RFC 1122. Instead, aggregate them, and respond
once in the egress function.
However, still instantly send challenge ACKs to trigger fast
retransmit.
Commit 21282fdb was not completely sufficient because e.g. receiving
one octet and then blocking meant that an ACK with window length
of one is then sent, and this isn't motivating the other TCP stacks
all that much.
In any case, preemptively notifying the peer of window size increase
can only be beneficial, modulo network congestion.
Zero is a valid sequence number, treating it as an absence of value
isn't any good. This is unlikely to cause any real harm but it
just isn't good practice, nor does it make for understandable code.
Before this commit, if the amount of data in the buffer caused it
to be split among many outgoing packets, and retransmit timer
was active, the socket would behave very erratically and flood
the peer.
Before this commit, anything that touched RawSocket or TapInterface
worked partly by accident and partly because of a horrible crutch
that resulted in massive latencies as well as inevitable packet loss
every time an ARP request had to be issued. Also, there was no way
to use poll() other than by continuously calling it in a busy loop.
After this commit, poll() indicates when the earliest timer expires,
and so the caller can sleep until that moment (or until packets
arrive).
Note that there is a subtle problem remaining: every time poll()
is called, every socket with a pending outbound packet whose
IP address doesn't correspond to a MAC address will send a new
ARP request, resulting in potentially a whole lot of such requests.
ARP rate limiting is a separate topic though.