gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/net/internal/socket/socket_dontwait_test.go (about)

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
     6  // +build darwin dragonfly freebsd linux netbsd openbsd solaris
     7  
     8  package socket_test
     9  
    10  import (
    11  	"bytes"
    12  	"errors"
    13  	"net"
    14  	"runtime"
    15  	"syscall"
    16  	"testing"
    17  
    18  	"gitee.com/ks-custle/core-gm/net/internal/socket"
    19  	"gitee.com/ks-custle/core-gm/net/nettest"
    20  )
    21  
    22  func TestUDPDontwait(t *testing.T) {
    23  	c, err := nettest.NewLocalPacketListener("udp")
    24  	if err != nil {
    25  		t.Skipf("not supported on %s/%s: %v", runtime.GOOS, runtime.GOARCH, err)
    26  	}
    27  	defer c.Close()
    28  	cc, err := socket.NewConn(c.(*net.UDPConn))
    29  	if err != nil {
    30  		t.Fatal(err)
    31  	}
    32  	isErrWouldblock := func(err error) bool {
    33  		var errno syscall.Errno
    34  		return errors.As(err, &errno) && (errno == syscall.EAGAIN || errno == syscall.EWOULDBLOCK)
    35  	}
    36  
    37  	t.Run("Message-dontwait", func(t *testing.T) {
    38  		// Read before something was sent; expect EWOULDBLOCK
    39  		b := make([]byte, 32)
    40  		rm := socket.Message{
    41  			Buffers: [][]byte{b},
    42  		}
    43  		if err := cc.RecvMsg(&rm, syscall.MSG_DONTWAIT); !isErrWouldblock(err) {
    44  			t.Fatal(err)
    45  		}
    46  		// To trigger EWOULDBLOCK by SendMsg, we have to send faster than what the
    47  		// system/network is able to process. Whether or not we can trigger this
    48  		// depends on the system, specifically on write buffer sizes and the speed
    49  		// of the network interface.
    50  		// We cannot expect to quickly and reliably trigger this, especially not
    51  		// because this test sends data over a (fast) loopback. Consequently, we
    52  		// only check that sending with MSG_DONTWAIT works at all and don't attempt
    53  		// testing that we would eventually get EWOULDBLOCK here.
    54  		data := []byte("HELLO-R-U-THERE")
    55  		wm := socket.Message{
    56  			Buffers: [][]byte{data},
    57  			Addr:    c.LocalAddr(),
    58  		}
    59  		// Send one message, repeat until we don't get EWOULDBLOCK. This will likely succeed at the first attempt.
    60  		for {
    61  			err := cc.SendMsg(&wm, syscall.MSG_DONTWAIT)
    62  			if err == nil {
    63  				break
    64  			} else if !isErrWouldblock(err) {
    65  				t.Fatal(err)
    66  			}
    67  		}
    68  		// Read the message now available; again, this will likely succeed at the first attempt.
    69  		for {
    70  			err := cc.RecvMsg(&rm, syscall.MSG_DONTWAIT)
    71  			if err == nil {
    72  				break
    73  			} else if !isErrWouldblock(err) {
    74  				t.Fatal(err)
    75  			}
    76  		}
    77  		if !bytes.Equal(b[:rm.N], data) {
    78  			t.Fatalf("got %#v; want %#v", b[:rm.N], data)
    79  		}
    80  	})
    81  	switch runtime.GOOS {
    82  	case "android", "linux":
    83  		t.Run("Messages", func(t *testing.T) {
    84  			data := []byte("HELLO-R-U-THERE")
    85  			wmbs := bytes.SplitAfter(data, []byte("-"))
    86  			wms := []socket.Message{
    87  				{Buffers: wmbs[:1], Addr: c.LocalAddr()},
    88  				{Buffers: wmbs[1:], Addr: c.LocalAddr()},
    89  			}
    90  			b := make([]byte, 32)
    91  			rmbs := [][][]byte{{b[:len(wmbs[0])]}, {b[len(wmbs[0]):]}}
    92  			rms := []socket.Message{
    93  				{Buffers: rmbs[0]},
    94  				{Buffers: rmbs[1]},
    95  			}
    96  			_, err := cc.RecvMsgs(rms, syscall.MSG_DONTWAIT)
    97  			if !isErrWouldblock(err) {
    98  				t.Fatal(err)
    99  			}
   100  			for ntot := 0; ntot < len(wms); {
   101  				n, err := cc.SendMsgs(wms[ntot:], syscall.MSG_DONTWAIT)
   102  				if err == nil {
   103  					ntot += n
   104  				} else if !isErrWouldblock(err) {
   105  					t.Fatal(err)
   106  				}
   107  			}
   108  			for ntot := 0; ntot < len(rms); {
   109  				n, err := cc.RecvMsgs(rms[ntot:], syscall.MSG_DONTWAIT)
   110  				if err == nil {
   111  					ntot += n
   112  				} else if !isErrWouldblock(err) {
   113  					t.Fatal(err)
   114  				}
   115  			}
   116  			nn := 0
   117  			for i := 0; i < len(rms); i++ {
   118  				nn += rms[i].N
   119  			}
   120  			if !bytes.Equal(b[:nn], data) {
   121  				t.Fatalf("got %#v; want %#v", b[:nn], data)
   122  			}
   123  		})
   124  	}
   125  }