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 }