github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/packetimpact/tests/tcp_rcv_buf_space_test.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package tcp_rcv_buf_space_test 16 17 import ( 18 "context" 19 "flag" 20 "testing" 21 22 "golang.org/x/sys/unix" 23 "github.com/SagerNet/gvisor/pkg/tcpip/header" 24 "github.com/SagerNet/gvisor/test/packetimpact/testbench" 25 ) 26 27 func init() { 28 testbench.Initialize(flag.CommandLine) 29 } 30 31 // TestReduceRecvBuf tests that a packet within window is still dropped 32 // if the available buffer space drops below the size of the incoming 33 // segment. 34 func TestReduceRecvBuf(t *testing.T) { 35 dut := testbench.NewDUT(t) 36 listenFd, remotePort := dut.CreateListener(t, unix.SOCK_STREAM, unix.IPPROTO_TCP, 1) 37 defer dut.Close(t, listenFd) 38 conn := dut.Net.NewTCPIPv4(t, testbench.TCP{DstPort: &remotePort}, testbench.TCP{SrcPort: &remotePort}) 39 defer conn.Close(t) 40 41 conn.Connect(t) 42 acceptFd, _ := dut.Accept(t, listenFd) 43 defer dut.Close(t, acceptFd) 44 45 // Set a small receive buffer for the test. 46 const rcvBufSz = 4096 47 dut.SetSockOptInt(t, acceptFd, unix.SOL_SOCKET, unix.SO_RCVBUF, rcvBufSz) 48 49 // Retrieve the actual buffer. 50 bufSz := dut.GetSockOptInt(t, acceptFd, unix.SOL_SOCKET, unix.SO_RCVBUF) 51 52 // Generate a payload of 1 more than the actual buffer size used by the 53 // DUT. 54 sampleData := testbench.GenerateRandomPayload(t, int(bufSz)+1) 55 // Send and receive sample data to the dut. 56 const pktSize = 1400 57 for payload := sampleData; len(payload) != 0; { 58 payloadBytes := pktSize 59 if l := len(payload); l < payloadBytes { 60 payloadBytes = l 61 } 62 63 conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)}, []testbench.Layer{&testbench.Payload{Bytes: payload[:payloadBytes]}}...) 64 payload = payload[payloadBytes:] 65 } 66 67 // First read should read < len(sampleData) 68 if ret, _, err := dut.RecvWithErrno(context.Background(), t, acceptFd, int32(len(sampleData)), 0); ret == -1 || int(ret) == len(sampleData) { 69 t.Fatalf("dut.RecvWithErrno(ctx, t, %d, %d, 0) = %d,_, %s", acceptFd, int32(len(sampleData)), ret, err) 70 } 71 72 // Second read should return EAGAIN as the last segment should have been 73 // dropped due to it exceeding the receive buffer space available in the 74 // socket. 75 if ret, got, err := dut.RecvWithErrno(context.Background(), t, acceptFd, int32(len(sampleData)), unix.MSG_DONTWAIT); got != nil || ret != -1 || err != unix.EAGAIN { 76 t.Fatalf("expected no packets but got: %s", got) 77 } 78 }