Add Sniffer.Drain() draining socket receive buffer

Add Sniffer.Drain() which drains the socket's receive buffer by temporarily
setting the socket to non-blocking, and receiving in a loop until EINTR,
EWOULDBLOCK or EAGAIN. This method should be used when long periods of time
elapses without receiving on the socket, because uninteresting packets may have
piled up in the receive buffer, filling it up and causing packets critical to
test operation to be dropped.

PiperOrigin-RevId: 306380480
This commit is contained in:
gVisor bot 2020-04-13 23:04:01 -07:00
parent 71e6ac3e1f
commit c230d12b5c
3 changed files with 37 additions and 0 deletions

View File

@ -228,6 +228,12 @@ func (conn *TCPIPv4) RecvFrame(timeout time.Duration) Layers {
return nil
}
// Drain drains the sniffer's receive buffer by receiving packets until there's
// nothing else to receive.
func (conn *TCPIPv4) Drain() {
conn.sniffer.Drain()
}
// Expect a packet that matches the provided tcp within the timeout specified.
// If it doesn't arrive in time, it returns nil.
func (conn *TCPIPv4) Expect(tcp TCP, timeout time.Duration) (*TCP, error) {
@ -423,6 +429,12 @@ func (conn *UDPIPv4) Recv(timeout time.Duration) *UDP {
return nil
}
// Drain drains the sniffer's receive buffer by receiving packets until there's
// nothing else to receive.
func (conn *UDPIPv4) Drain() {
conn.sniffer.Drain()
}
// Expect a packet that matches the provided udp within the timeout specified.
// If it doesn't arrive in time, the test fails.
func (conn *UDPIPv4) Expect(udp UDP, timeout time.Duration) (*UDP, error) {

View File

@ -97,6 +97,29 @@ func (s *Sniffer) Recv(timeout time.Duration) []byte {
}
}
// Drain drains the Sniffer's socket receive buffer by receiving until there's
// nothing else to receive.
func (s *Sniffer) Drain() {
s.t.Helper()
flags, err := unix.FcntlInt(uintptr(s.fd), unix.F_GETFL, 0)
if err != nil {
s.t.Fatalf("failed to get sniffer socket fd flags: %s", err)
}
if _, err := unix.FcntlInt(uintptr(s.fd), unix.F_SETFL, flags|unix.O_NONBLOCK); err != nil {
s.t.Fatalf("failed to make sniffer socket non-blocking: %s", err)
}
for {
buf := make([]byte, maxReadSize)
_, _, err := unix.Recvfrom(s.fd, buf, unix.MSG_TRUNC)
if err == unix.EINTR || err == unix.EAGAIN || err == unix.EWOULDBLOCK {
break
}
}
if _, err := unix.FcntlInt(uintptr(s.fd), unix.F_SETFL, flags); err != nil {
s.t.Fatalf("failed to restore sniffer socket fd flags: %s", err)
}
}
// Close the socket that Sniffer is using.
func (s *Sniffer) Close() {
if err := unix.Close(s.fd); err != nil {

View File

@ -53,6 +53,8 @@ func TestFinWait2Timeout(t *testing.T) {
conn.Send(tb.TCP{Flags: tb.Uint8(header.TCPFlagAck)})
time.Sleep(5 * time.Second)
conn.Drain()
conn.Send(tb.TCP{Flags: tb.Uint8(header.TCPFlagAck)})
if tt.linger2 {
if _, err := conn.Expect(tb.TCP{Flags: tb.Uint8(header.TCPFlagRst)}, time.Second); err != nil {