github.com/pawelgaczynski/giouring@v0.0.0-20230826085535-69588b89acb9/network_test.go (about)

     1  // MIT License
     2  //
     3  // Copyright (c) 2023 Paweł Gaczyński
     4  //
     5  // Permission is hereby granted, free of charge, to any person obtaining a
     6  // copy of this software and associated documentation files (the
     7  // "Software"), to deal in the Software without restriction, including
     8  // without limitation the rights to use, copy, modify, merge, publish,
     9  // distribute, sublicense, and/or sell copies of the Software, and to
    10  // permit persons to whom the Software is furnished to do so, subject to
    11  // the following conditions:
    12  //
    13  // The above copyright notice and this permission notice shall be included
    14  // in all copies or substantial portions of the Software.
    15  //
    16  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    17  // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    18  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    19  // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    20  // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    21  // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    22  // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    23  
    24  package giouring
    25  
    26  import (
    27  	"errors"
    28  	"fmt"
    29  	"net"
    30  	"sync"
    31  	"syscall"
    32  	"testing"
    33  	"time"
    34  	"unsafe"
    35  
    36  	. "github.com/stretchr/testify/require"
    37  	"golang.org/x/sys/unix"
    38  )
    39  
    40  const (
    41  	acceptFlag uint64 = 1 << (64 - 1 - iota)
    42  	recvFlag
    43  	sendFlag
    44  	closeFlag
    45  )
    46  
    47  const allFlagsMask = acceptFlag | recvFlag | sendFlag | closeFlag
    48  
    49  const (
    50  	acceptState = iota
    51  	recvState
    52  	sendState
    53  	closeState
    54  )
    55  
    56  type tcpConn struct {
    57  	buffer   []byte
    58  	iovecs   []syscall.Iovec
    59  	msg      *syscall.Msghdr
    60  	sockAddr *syscall.RawSockaddrAny
    61  	fd       int
    62  	state    uint8
    63  
    64  	receivedCount uint
    65  }
    66  
    67  type networkTester struct {
    68  	connections map[int]*tcpConn
    69  
    70  	clientAddr *unix.RawSockaddrAny
    71  	clientLen  *uint32
    72  
    73  	clientAddrPointer uintptr
    74  	clientLenPointer  uint64
    75  
    76  	accpepted uint
    77  }
    78  
    79  var prepareSingleAccept = func(t *testing.T, context testContext, entry *SubmissionQueueEntry) {
    80  	socketFd, ok := context["socketFd"].(int)
    81  	True(t, ok)
    82  	clientAddrPointer, ok := context["clientAddrPointer"].(uintptr)
    83  	True(t, ok)
    84  	clientLenPointer, ok := context["clientLenPointer"].(uint64)
    85  	True(t, ok)
    86  	entry.PrepareAccept(socketFd, clientAddrPointer, clientLenPointer, 0)
    87  }
    88  
    89  func newNetworkTester() *networkTester {
    90  	clientLen := new(uint32)
    91  	clientAddr := &unix.RawSockaddrAny{}
    92  	*clientLen = unix.SizeofSockaddrAny
    93  	clientAddrPointer := uintptr(unsafe.Pointer(clientAddr))
    94  	clientLenPointer := uint64(uintptr(unsafe.Pointer(clientLen)))
    95  
    96  	return &networkTester{
    97  		connections:       make(map[int]*tcpConn),
    98  		clientAddr:        clientAddr,
    99  		clientLen:         clientLen,
   100  		clientAddrPointer: clientAddrPointer,
   101  		clientLenPointer:  clientLenPointer,
   102  	}
   103  }
   104  
   105  func (tester *networkTester) getConnection(fd int) *tcpConn {
   106  	if val, ok := tester.connections[fd]; ok {
   107  		return val
   108  	}
   109  
   110  	buffer := make([]byte, 1024)
   111  	iovecs := make([]syscall.Iovec, 1)
   112  	iovecs[0] = syscall.Iovec{
   113  		Base: &buffer[0],
   114  		Len:  uint64(len(buffer)),
   115  	}
   116  
   117  	var (
   118  		msg      syscall.Msghdr
   119  		sockAddr syscall.RawSockaddrAny
   120  	)
   121  
   122  	sizeOfSockAddr := unsafe.Sizeof(sockAddr)
   123  	msg.Name = (*byte)(unsafe.Pointer(&sockAddr))
   124  	msg.Namelen = uint32(sizeOfSockAddr)
   125  	msg.Iov = &iovecs[0]
   126  	msg.Iovlen = 1
   127  
   128  	controlLen := cmsgAlign(uint64(sizeOfSockAddr)) + syscall.SizeofCmsghdr
   129  	controlBuffer := make([]byte, controlLen)
   130  	msg.Control = (*byte)(unsafe.Pointer(&controlBuffer[0]))
   131  	msg.SetControllen(int(controlLen))
   132  
   133  	connection := &tcpConn{state: acceptState, buffer: buffer, iovecs: iovecs, fd: fd, msg: &msg, sockAddr: &sockAddr}
   134  	tester.connections[fd] = connection
   135  
   136  	return connection
   137  }
   138  
   139  func (tester *networkTester) loop(
   140  	t *testing.T, scenario networkTestScenario, ctx testContext, ring *Ring, expectedRWLoops uint,
   141  ) bool {
   142  	t.Helper()
   143  
   144  	socketVal, ok := ctx["socketFd"]
   145  	True(t, ok)
   146  	socketFd, ok := socketVal.(int)
   147  	True(t, ok)
   148  
   149  	cqe, err := ring.WaitCQE()
   150  	if errors.Is(err, syscall.EAGAIN) || errors.Is(err, syscall.EINTR) ||
   151  		errors.Is(err, syscall.ETIME) {
   152  		return false
   153  	}
   154  	Nil(t, err)
   155  
   156  	ring.CQESeen(cqe)
   157  
   158  	if cqe.UserData&acceptFlag != 0 {
   159  		tester.accpepted++
   160  
   161  		Equal(t, uint64(socketFd), cqe.UserData^acceptFlag)
   162  		GreaterOrEqual(t, cqe.Res, int32(0))
   163  		fd := int(cqe.Res)
   164  		conn := tester.getConnection(fd)
   165  
   166  		entry := ring.GetSQE()
   167  		NotNil(t, entry)
   168  		scenario.prepareRecv(t, ctx, conn, entry)
   169  
   170  		entry.UserData = recvFlag | uint64(conn.fd)
   171  		conn.state = recvState
   172  
   173  		if scenario.repeatAccept && tester.accpepted < scenario.clientsNumber {
   174  			var cqeNr uint
   175  			cqeNr, err = ring.Submit()
   176  			Nil(t, err)
   177  			Equal(t, uint(1), cqeNr)
   178  			entry = ring.GetSQE()
   179  			NotNil(t, entry)
   180  			scenario.prepareAccept(t, ctx, entry)
   181  			entry.UserData = acceptFlag | uint64(socketFd)
   182  		}
   183  
   184  		var cqeNr uint
   185  		cqeNr, err = ring.Submit()
   186  		Nil(t, err)
   187  		Equal(t, uint(1), cqeNr)
   188  	} else {
   189  		conn := tester.getConnection(int(cqe.UserData & ^allFlagsMask))
   190  
   191  		switch {
   192  		case cqe.UserData&recvFlag != 0:
   193  			conn.receivedCount++
   194  
   195  			Equal(t, conn.fd, int(cqe.UserData & ^allFlagsMask))
   196  
   197  			var recvLength int32 = 18
   198  			if scenario.recvLengthProvider != nil {
   199  				recvLength = scenario.recvLengthProvider()
   200  			}
   201  
   202  			Equal(t, recvLength, cqe.Res)
   203  
   204  			dataRecevied := scenario.recvDataProvider(ctx, conn, cqe)
   205  			Equal(t, "testdata1234567890", string(dataRecevied))
   206  			conn.buffer = conn.buffer[:0]
   207  			data := []byte("responsedata0123456789")
   208  			copied := copy(conn.buffer[:len(data)], data)
   209  			Equal(t, 22, copied)
   210  			buffer := conn.buffer[:len(data)]
   211  
   212  			entry := ring.GetSQE()
   213  			NotNil(t, entry)
   214  			scenario.prepareSend(t, ctx, conn, buffer, entry)
   215  
   216  			entry.UserData = sendFlag | uint64(conn.fd)
   217  			conn.state = sendState
   218  			var cqeNr uint
   219  			cqeNr, err = ring.Submit()
   220  			Nil(t, err)
   221  			Equal(t, uint(1), cqeNr)
   222  
   223  		case cqe.UserData&sendFlag != 0:
   224  			Equal(t, uint64(conn.fd), cqe.UserData & ^allFlagsMask)
   225  			Greater(t, cqe.Res, int32(0))
   226  
   227  			if conn.receivedCount == expectedRWLoops {
   228  				entry := ring.GetSQE()
   229  				NotNil(t, entry)
   230  				scenario.prepareClose(t, ctx, conn, entry)
   231  
   232  				entry.UserData = closeFlag | uint64(conn.fd)
   233  				conn.state = closeState
   234  				var cqeNr uint
   235  				cqeNr, err = ring.Submit()
   236  				Nil(t, err)
   237  				Equal(t, uint(1), cqeNr)
   238  			}
   239  		case cqe.UserData&closeFlag != 0:
   240  			Equal(t, uint64(conn.fd), cqe.UserData & ^allFlagsMask)
   241  			Equal(t, int32(0), cqe.Res)
   242  
   243  			delete(tester.connections, conn.fd)
   244  
   245  			return true
   246  		}
   247  	}
   248  
   249  	return false
   250  }
   251  
   252  type networkTestScenario struct {
   253  	ringFlags     uint32
   254  	setup         func(*testing.T, testContext, *Ring)
   255  	clientsNumber uint
   256  	repeatAccept  bool
   257  	rwLoopNumber  uint
   258  	recvMulti     bool
   259  
   260  	prepareAccept func(*testing.T, testContext, *SubmissionQueueEntry)
   261  	prepareRecv   func(*testing.T, testContext, *tcpConn, *SubmissionQueueEntry)
   262  	prepareSend   func(*testing.T, testContext, *tcpConn, []byte, *SubmissionQueueEntry)
   263  	prepareClose  func(*testing.T, testContext, *tcpConn, *SubmissionQueueEntry)
   264  
   265  	recvDataProvider   func(testContext, *tcpConn, *CompletionQueueEvent) []byte
   266  	recvLengthProvider func() int32
   267  }
   268  
   269  func testNetwork(t *testing.T, scenario networkTestScenario) {
   270  	t.Helper()
   271  
   272  	var wg sync.WaitGroup
   273  	wg.Add(1)
   274  
   275  	var expectedLoopCount uint = 1
   276  	var loopCount uint
   277  
   278  	if scenario.clientsNumber > 0 {
   279  		expectedLoopCount = scenario.clientsNumber
   280  	}
   281  
   282  	go func() {
   283  		ring := NewRing()
   284  		err := ring.QueueInit(64, scenario.ringFlags)
   285  		NoError(t, err)
   286  
   287  		context := make(map[string]interface{})
   288  
   289  		if scenario.setup != nil {
   290  			scenario.setup(t, context, ring)
   291  		}
   292  
   293  		defer func() {
   294  			ring.QueueExit()
   295  		}()
   296  
   297  		socketFd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, 0)
   298  		Nil(t, err)
   299  		err = syscall.SetsockoptInt(socketFd, syscall.SOL_SOCKET, unix.SO_REUSEADDR, 1)
   300  		Nil(t, err)
   301  		err = syscall.SetsockoptInt(socketFd, syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1)
   302  		Nil(t, err)
   303  		testPort := getTestPort()
   304  
   305  		err = syscall.Bind(socketFd, &syscall.SockaddrInet4{
   306  			Port: testPort,
   307  		})
   308  		Nil(t, err)
   309  		err = syscall.SetNonblock(socketFd, false)
   310  		Nil(t, err)
   311  		err = syscall.Listen(socketFd, 128)
   312  		Nil(t, err)
   313  
   314  		defer func() {
   315  			closeErr := syscall.Close(socketFd)
   316  			Nil(t, closeErr)
   317  		}()
   318  
   319  		entry := ring.GetSQE()
   320  		NotNil(t, entry)
   321  
   322  		tester := newNetworkTester()
   323  		context["clientAddrPointer"] = tester.clientAddrPointer
   324  		context["clientLenPointer"] = tester.clientLenPointer
   325  		context["socketFd"] = socketFd
   326  
   327  		scenario.prepareAccept(t, context, entry)
   328  		entry.UserData = acceptFlag | uint64(socketFd)
   329  
   330  		cqeNr, err := ring.Submit()
   331  		Nil(t, err)
   332  		Equal(t, uint(1), cqeNr)
   333  
   334  		var expectedRWLoops uint = 1
   335  		if scenario.rwLoopNumber > 0 {
   336  			expectedRWLoops = scenario.rwLoopNumber
   337  		}
   338  
   339  		go func() {
   340  			for i := 0; i < int(expectedLoopCount); i++ {
   341  				var (
   342  					cErr error
   343  					conn net.Conn
   344  				)
   345  				conn, cErr = net.DialTimeout("tcp", fmt.Sprintf("127.0.0.1:%d", testPort), time.Second)
   346  				Nil(t, cErr)
   347  				NotNil(t, conn)
   348  
   349  				for j := 0; j < int(expectedRWLoops); j++ {
   350  					var bytesWritten int
   351  					bytesWritten, cErr = conn.Write([]byte("testdata1234567890"))
   352  					Nil(t, cErr)
   353  					Equal(t, 18, bytesWritten)
   354  
   355  					var buffer [22]byte
   356  					bytesWritten, cErr = conn.Read(buffer[:])
   357  					Nil(t, cErr)
   358  					Equal(t, 22, bytesWritten)
   359  					Equal(t, "responsedata0123456789", string(buffer[:]))
   360  
   361  					if tcpConn, ok := conn.(*net.TCPConn); ok {
   362  						lErr := tcpConn.SetLinger(0)
   363  						Nil(t, lErr)
   364  					}
   365  				}
   366  			}
   367  		}()
   368  
   369  		for {
   370  			if tester.loop(t, scenario, context, ring, expectedRWLoops) {
   371  				loopCount++
   372  				if loopCount == expectedLoopCount {
   373  					break
   374  				}
   375  			}
   376  		}
   377  		wg.Done()
   378  	}()
   379  
   380  	wg.Wait()
   381  }
   382  
   383  func TestAcceptSendRecvTCP(t *testing.T) {
   384  	testNetwork(t, networkTestScenario{
   385  		prepareAccept: prepareSingleAccept,
   386  		prepareRecv: func(t *testing.T, ctx testContext, conn *tcpConn, entry *SubmissionQueueEntry) {
   387  			entry.PrepareRecv(
   388  				conn.fd, uintptr(unsafe.Pointer(&conn.buffer[0])), uint32(len(conn.buffer)), 0)
   389  		},
   390  		prepareSend: func(t *testing.T, ctx testContext, conn *tcpConn, buffer []byte, entry *SubmissionQueueEntry) {
   391  			entry.PrepareSend(
   392  				conn.fd, uintptr(unsafe.Pointer(&buffer[0])), uint32(len(buffer)), 0)
   393  		},
   394  		prepareClose: func(t *testing.T, ctx testContext, conn *tcpConn, entry *SubmissionQueueEntry) {
   395  			entry.PrepareClose(conn.fd)
   396  		},
   397  
   398  		recvDataProvider: func(ctx testContext, conn *tcpConn, cqe *CompletionQueueEvent) []byte {
   399  			return conn.buffer[:18]
   400  		},
   401  	})
   402  }
   403  
   404  func TestAcceptReadWriteTCP(t *testing.T) {
   405  	testNetwork(t, networkTestScenario{
   406  		prepareAccept: prepareSingleAccept,
   407  		prepareRecv: func(t *testing.T, context testContext, conn *tcpConn, entry *SubmissionQueueEntry) {
   408  			entry.PrepareRead(conn.fd, uintptr(unsafe.Pointer(&conn.buffer[0])), uint32(len(conn.buffer)), 0)
   409  		},
   410  		prepareSend: func(t *testing.T, context testContext, conn *tcpConn, buffer []byte, entry *SubmissionQueueEntry) {
   411  			entry.PrepareWrite(
   412  				conn.fd, uintptr(unsafe.Pointer(&buffer[0])), uint32(len(buffer)), 0)
   413  		},
   414  		prepareClose: func(t *testing.T, tc testContext, conn *tcpConn, entry *SubmissionQueueEntry) {
   415  			entry.PrepareClose(conn.fd)
   416  		},
   417  
   418  		recvDataProvider: func(ctx testContext, conn *tcpConn, cqe *CompletionQueueEvent) []byte {
   419  			return conn.buffer[:18]
   420  		},
   421  	})
   422  }
   423  
   424  func TestAcceptReadvWritevTCP(t *testing.T) {
   425  	testNetwork(t, networkTestScenario{
   426  		prepareAccept: prepareSingleAccept,
   427  		prepareRecv: func(t *testing.T, context testContext, conn *tcpConn, entry *SubmissionQueueEntry) {
   428  			entry.PrepareReadv(conn.fd, uintptr(unsafe.Pointer(&conn.iovecs[0])), uint32(len(conn.iovecs)), 0)
   429  		},
   430  		prepareSend: func(t *testing.T, context testContext, conn *tcpConn, buffer []byte, entry *SubmissionQueueEntry) {
   431  			entry.PrepareWritev(
   432  				conn.fd, uintptr(unsafe.Pointer(&conn.iovecs[0])), uint32(len(conn.iovecs)), 0)
   433  		},
   434  		prepareClose: func(t *testing.T, tc testContext, conn *tcpConn, entry *SubmissionQueueEntry) {
   435  			entry.PrepareClose(conn.fd)
   436  		},
   437  
   438  		recvDataProvider: func(ctx testContext, conn *tcpConn, cqe *CompletionQueueEvent) []byte {
   439  			return conn.buffer[:18]
   440  		},
   441  	})
   442  }
   443  
   444  func TestMultiAcceptMultiRecvTCP(t *testing.T) {
   445  	testNetwork(t, networkTestScenario{
   446  		clientsNumber: 2,
   447  		repeatAccept:  false,
   448  		rwLoopNumber:  4,
   449  		setup: func(t *testing.T, ctx testContext, ring *Ring) {
   450  			buffers := make([][]byte, 16)
   451  			ts := syscall.NsecToTimespec((time.Millisecond).Nanoseconds())
   452  			for i := 0; i < len(buffers); i++ {
   453  				buffers[i] = make([]byte, 1024)
   454  
   455  				sqe := ring.GetSQE()
   456  				NotNil(t, sqe)
   457  
   458  				sqe.PrepareProvideBuffers(uintptr(unsafe.Pointer(&buffers[i][0])), len(buffers[i]), 1, 7, i)
   459  				sqe.UserData = 777
   460  
   461  				cqe, err := ring.SubmitAndWaitTimeout(1, &ts, nil)
   462  				NoError(t, err)
   463  				NotNil(t, cqe)
   464  
   465  				ring.CQESeen(cqe)
   466  			}
   467  			ctx["buffers"] = buffers
   468  		},
   469  		prepareAccept: func(t *testing.T, context testContext, entry *SubmissionQueueEntry) {
   470  			socketFd, ok := context["socketFd"].(int)
   471  			True(t, ok)
   472  			clientAddrPointer, ok := context["clientAddrPointer"].(uintptr)
   473  			True(t, ok)
   474  			clientLenPointer, ok := context["clientLenPointer"].(uint64)
   475  			True(t, ok)
   476  
   477  			entry.PrepareMultishotAccept(socketFd, clientAddrPointer, clientLenPointer, 0)
   478  		},
   479  		prepareRecv: func(t *testing.T, context testContext, conn *tcpConn, entry *SubmissionQueueEntry) {
   480  			entry.PrepareRecvMultishot(conn.fd, 0, 0, 0)
   481  			entry.Flags |= SqeBufferSelect
   482  			entry.BufIG = 7
   483  		},
   484  		prepareSend: func(t *testing.T, context testContext, conn *tcpConn, buffer []byte, entry *SubmissionQueueEntry) {
   485  			entry.PrepareSend(
   486  				conn.fd, uintptr(unsafe.Pointer(&buffer[0])), uint32(len(buffer)), 0)
   487  		},
   488  		prepareClose: func(t *testing.T, tc testContext, conn *tcpConn, entry *SubmissionQueueEntry) {
   489  			entry.PrepareClose(conn.fd)
   490  		},
   491  
   492  		recvDataProvider: func(ctx testContext, conn *tcpConn, cqe *CompletionQueueEvent) []byte {
   493  			NotZero(t, cqe.Flags&CQEFBuffer)
   494  
   495  			bufferIdx := uint16(cqe.Flags >> CQEBufferShift)
   496  			buffers, ok := ctx["buffers"].([][]byte)
   497  			True(t, ok)
   498  
   499  			return buffers[bufferIdx][:18]
   500  		},
   501  	})
   502  }
   503  
   504  func TestRecvMsgSendMsgTCP(t *testing.T) {
   505  	testNetwork(t, networkTestScenario{
   506  		prepareAccept: prepareSingleAccept,
   507  		prepareRecv: func(t *testing.T, context testContext, conn *tcpConn, entry *SubmissionQueueEntry) {
   508  			entry.PrepareRecvMsg(conn.fd, conn.msg, 0)
   509  		},
   510  		prepareSend: func(t *testing.T, context testContext, conn *tcpConn, buffer []byte, entry *SubmissionQueueEntry) {
   511  			entry.PrepareSendMsg(conn.fd, conn.msg, 0)
   512  		},
   513  		prepareClose: func(t *testing.T, tc testContext, conn *tcpConn, entry *SubmissionQueueEntry) {
   514  			entry.PrepareClose(conn.fd)
   515  		},
   516  
   517  		recvDataProvider: func(ctx testContext, conn *tcpConn, cqe *CompletionQueueEvent) []byte {
   518  			return conn.buffer[:18]
   519  		},
   520  	})
   521  }
   522  
   523  func TestRecvMsgMultiSendTCP(t *testing.T) {
   524  	testNetwork(t, networkTestScenario{
   525  		rwLoopNumber: 4,
   526  		recvMulti:    true,
   527  		setup: func(t *testing.T, ctx testContext, ring *Ring) {
   528  			buffers := make([][]byte, 16)
   529  			ts := syscall.NsecToTimespec((time.Millisecond).Nanoseconds())
   530  			for i := 0; i < len(buffers); i++ {
   531  				buffers[i] = make([]byte, 1024)
   532  
   533  				sqe := ring.GetSQE()
   534  				NotNil(t, sqe)
   535  
   536  				sqe.PrepareProvideBuffers(uintptr(unsafe.Pointer(&buffers[i][0])), len(buffers[i]), 1, 7, i)
   537  				sqe.UserData = 777
   538  
   539  				cqe, err := ring.SubmitAndWaitTimeout(1, &ts, nil)
   540  				NoError(t, err)
   541  				NotNil(t, cqe)
   542  
   543  				ring.CQESeen(cqe)
   544  			}
   545  			ctx["buffers"] = buffers
   546  		},
   547  		prepareAccept: prepareSingleAccept,
   548  		prepareRecv: func(t *testing.T, context testContext, conn *tcpConn, entry *SubmissionQueueEntry) {
   549  			entry.PrepareRecvMsgMultishot(conn.fd, conn.msg, 0)
   550  			entry.Flags |= SqeBufferSelect
   551  			entry.BufIG = 7
   552  		},
   553  		prepareSend: func(t *testing.T, ctx testContext, conn *tcpConn, buffer []byte, entry *SubmissionQueueEntry) {
   554  			entry.PrepareSend(conn.fd, uintptr(unsafe.Pointer(&buffer[0])), uint32(len(buffer)), 0)
   555  		},
   556  		prepareClose: func(t *testing.T, tc testContext, conn *tcpConn, entry *SubmissionQueueEntry) {
   557  			entry.PrepareClose(conn.fd)
   558  		},
   559  
   560  		recvDataProvider: func(ctx testContext, conn *tcpConn, cqe *CompletionQueueEvent) []byte {
   561  			NotZero(t, cqe.Flags&CQEFBuffer)
   562  
   563  			bufferIdx := uint16(cqe.Flags >> CQEBufferShift)
   564  			buffers, ok := ctx["buffers"].([][]byte)
   565  			True(t, ok)
   566  
   567  			buffer := buffers[bufferIdx]
   568  			recvmsgOut := RecvmsgValidate(unsafe.Pointer(&buffer[0]), int(cqe.Res), conn.msg)
   569  			NotNil(t, recvmsgOut)
   570  			Equal(t, uint32(18), recvmsgOut.PayloadLen)
   571  
   572  			// TODO: name validation
   573  			name := recvmsgOut.Name()
   574  			NotNil(t, name)
   575  
   576  			payloadLength := recvmsgOut.PayloadLength(int(cqe.Res), conn.msg)
   577  			Equal(t, uint32(18), payloadLength)
   578  
   579  			payload := recvmsgOut.Payload(conn.msg)
   580  
   581  			return unsafe.Slice((*byte)(payload), payloadLength)
   582  		},
   583  		recvLengthProvider: func() int32 {
   584  			return 274
   585  		},
   586  	})
   587  }
   588  
   589  const (
   590  	bufferSize      = 1024
   591  	numberOfBuffers = 16
   592  )
   593  
   594  func getBuffer(bufferBase uintptr, idx int) uintptr {
   595  	return bufferBase + uintptr((idx * bufferSize))
   596  }
   597  
   598  func recycleBuffer(bufRing *BufAndRing, bufferBase uintptr, idx int) {
   599  	bufRing.BufRingAdd(getBuffer(bufferBase, idx), bufferSize, uint16(idx), BufRingMask(numberOfBuffers), 0)
   600  	bufRing.BufRingAdvance(1)
   601  }
   602  
   603  func TestMultiAcceptMultiRecvMultiDirectBufRingTCP(t *testing.T) {
   604  	testNetwork(t, networkTestScenario{
   605  		clientsNumber: 2,
   606  		repeatAccept:  false,
   607  		rwLoopNumber:  4,
   608  		setup: func(t *testing.T, ctx testContext, ring *Ring) {
   609  			fds := make([]int, 16)
   610  			for i := range fds {
   611  				fds[i] = -1
   612  			}
   613  			_, err := ring.RegisterFiles(fds)
   614  			NoError(t, err)
   615  			bufRingSize := int((unsafe.Sizeof(BufAndRing{}) + uintptr(bufferSize)) * uintptr(numberOfBuffers))
   616  			data, err := syscall.Mmap(
   617  				-1,
   618  				0,
   619  				bufRingSize,
   620  				syscall.PROT_READ|syscall.PROT_WRITE,
   621  				syscall.MAP_ANONYMOUS|syscall.MAP_PRIVATE,
   622  			)
   623  			NoError(t, err)
   624  			bufRing := (*BufAndRing)(unsafe.Pointer(&data[0]))
   625  
   626  			bufRing.BufRingInit()
   627  			reg := &BufReg{
   628  				RingAddr:    uint64(uintptr(unsafe.Pointer(bufRing))),
   629  				RingEntries: uint32(numberOfBuffers),
   630  				Bgid:        0,
   631  			}
   632  			bufferBase := uintptr(unsafe.Pointer(bufRing)) + uintptr(RingBufStructSize)*uintptr(numberOfBuffers)
   633  			_, err = ring.RegisterBufferRing(reg, 0)
   634  			NoError(t, err)
   635  			for i := 0; i < numberOfBuffers; i++ {
   636  				bufRing.BufRingAdd(getBuffer(bufferBase, i), bufferSize, uint16(i), BufRingMask(uint32(numberOfBuffers)), i)
   637  			}
   638  
   639  			bufRing.BufRingAdvance(numberOfBuffers)
   640  
   641  			ctx["bufferBase"] = bufferBase
   642  			ctx["bufRing"] = bufRing
   643  			ctx["fds"] = fds
   644  		},
   645  		prepareAccept: func(t *testing.T, context testContext, entry *SubmissionQueueEntry) {
   646  			socketFd, ok := context["socketFd"].(int)
   647  			True(t, ok)
   648  
   649  			entry.PrepareMultishotAcceptDirect(socketFd, 0, 0, 0)
   650  		},
   651  		prepareRecv: func(t *testing.T, context testContext, conn *tcpConn, entry *SubmissionQueueEntry) {
   652  			entry.PrepareRecvMultishot(conn.fd, 0, 0, 0)
   653  			entry.Flags |= SqeBufferSelect
   654  			entry.Flags |= SqeFixedFile
   655  		},
   656  		prepareSend: func(t *testing.T, ctx testContext, conn *tcpConn, buffer []byte, entry *SubmissionQueueEntry) {
   657  			entry.PrepareSend(
   658  				conn.fd, uintptr(unsafe.Pointer(&buffer[0])), uint32(len(buffer)), 0)
   659  			entry.Flags |= SqeFixedFile
   660  		},
   661  		prepareClose: func(t *testing.T, tc testContext, conn *tcpConn, entry *SubmissionQueueEntry) {
   662  			entry.PrepareCloseDirect(uint32(conn.fd))
   663  		},
   664  
   665  		recvDataProvider: func(ctx testContext, conn *tcpConn, cqe *CompletionQueueEvent) []byte {
   666  			NotZero(t, cqe.Flags&CQEFBuffer)
   667  			bufferIdx := int(cqe.Flags >> CQEBufferShift)
   668  			bufferBase, ok := ctx["bufferBase"].(uintptr)
   669  			True(t, ok)
   670  			bufRing, ok := ctx["bufRing"].(*BufAndRing)
   671  			True(t, ok)
   672  			bufPtr := getBuffer(bufferBase, bufferIdx)
   673  			ringBuffer := unsafe.Slice((*byte)(unsafe.Pointer(bufPtr)), bufferSize)
   674  
   675  			buffer := make([]byte, cqe.Res)
   676  			copy(buffer, ringBuffer[:cqe.Res])
   677  
   678  			recycleBuffer(bufRing, bufferBase, bufferIdx)
   679  
   680  			return buffer
   681  		},
   682  	})
   683  }