github.com/database64128/shadowsocks-go@v1.7.0/service/udp_nat_mmsg.go (about) 1 //go:build linux || netbsd 2 3 package service 4 5 import ( 6 "bytes" 7 "errors" 8 "net/netip" 9 "os" 10 "sync/atomic" 11 "time" 12 "unsafe" 13 14 "github.com/database64128/shadowsocks-go/conn" 15 "github.com/database64128/shadowsocks-go/router" 16 "github.com/database64128/shadowsocks-go/zerocopy" 17 "go.uber.org/zap" 18 "golang.org/x/sys/unix" 19 ) 20 21 // natUplinkMmsg is used for passing information about relay uplink to the relay goroutine. 22 type natUplinkMmsg struct { 23 clientAddrPort netip.AddrPort 24 natConn *conn.MmsgWConn 25 natConnSendCh <-chan *natQueuedPacket 26 natConnPacker zerocopy.ClientPacker 27 } 28 29 // natDownlinkMmsg is used for passing information about relay downlink to the relay goroutine. 30 type natDownlinkMmsg struct { 31 clientAddrPort netip.AddrPort 32 clientPktinfop *[]byte 33 clientPktinfo *atomic.Pointer[[]byte] 34 natConn *conn.MmsgRConn 35 natConnRecvBufSize int 36 natConnUnpacker zerocopy.ClientUnpacker 37 serverConn *conn.MmsgWConn 38 serverConnPacker zerocopy.ServerPacker 39 } 40 41 func (s *UDPNATRelay) setStartFunc(batchMode string) { 42 switch batchMode { 43 case "sendmmsg", "": 44 s.startFunc = s.startMmsg 45 default: 46 s.startFunc = s.startGeneric 47 } 48 } 49 50 func (s *UDPNATRelay) startMmsg() error { 51 serverConn, err := conn.ListenUDPRawConn(s.serverConnListenConfig, "udp", s.listenAddress) 52 if err != nil { 53 return err 54 } 55 s.serverConn = serverConn.UDPConn 56 57 s.mwg.Add(1) 58 59 go func() { 60 s.recvFromServerConnRecvmmsg(serverConn.RConn()) 61 s.mwg.Done() 62 }() 63 64 s.logger.Info("Started UDP NAT relay service", 65 zap.String("server", s.serverName), 66 zap.String("listenAddress", s.listenAddress), 67 ) 68 69 return nil 70 } 71 72 func (s *UDPNATRelay) recvFromServerConnRecvmmsg(serverConn *conn.MmsgRConn) { 73 n := s.serverRecvBatchSize 74 qpvec := make([]*natQueuedPacket, n) 75 namevec := make([]unix.RawSockaddrInet6, n) 76 iovec := make([]unix.Iovec, n) 77 cmsgvec := make([][]byte, n) 78 msgvec := make([]conn.Mmsghdr, n) 79 80 for i := range msgvec { 81 cmsgBuf := make([]byte, conn.SocketControlMessageBufferSize) 82 cmsgvec[i] = cmsgBuf 83 msgvec[i].Msghdr.Name = (*byte)(unsafe.Pointer(&namevec[i])) 84 msgvec[i].Msghdr.Namelen = unix.SizeofSockaddrInet6 85 msgvec[i].Msghdr.Iov = &iovec[i] 86 msgvec[i].Msghdr.SetIovlen(1) 87 msgvec[i].Msghdr.Control = &cmsgBuf[0] 88 } 89 90 var ( 91 err error 92 recvmmsgCount uint64 93 packetsReceived uint64 94 payloadBytesReceived uint64 95 burstBatchSize int 96 ) 97 98 for { 99 for i := range iovec[:n] { 100 queuedPacket := s.getQueuedPacket() 101 qpvec[i] = queuedPacket 102 iovec[i].Base = &queuedPacket.buf[s.packetBufFrontHeadroom] 103 iovec[i].SetLen(s.packetBufRecvSize) 104 msgvec[i].Msghdr.SetControllen(conn.SocketControlMessageBufferSize) 105 } 106 107 n, err = serverConn.ReadMsgs(msgvec, 0) 108 if err != nil { 109 if errors.Is(err, os.ErrDeadlineExceeded) { 110 break 111 } 112 113 s.logger.Warn("Failed to batch read packets from serverConn", 114 zap.String("server", s.serverName), 115 zap.String("listenAddress", s.listenAddress), 116 zap.Error(err), 117 ) 118 119 n = 1 120 s.putQueuedPacket(qpvec[0]) 121 continue 122 } 123 124 recvmmsgCount++ 125 packetsReceived += uint64(n) 126 if burstBatchSize < n { 127 burstBatchSize = n 128 } 129 130 s.mu.Lock() 131 132 msgvecn := msgvec[:n] 133 134 for i := range msgvecn { 135 msg := &msgvecn[i] 136 queuedPacket := qpvec[i] 137 138 if msg.Msghdr.Controllen == 0 { 139 s.logger.Warn("Skipping packet with no control message from serverConn", 140 zap.String("server", s.serverName), 141 zap.String("listenAddress", s.listenAddress), 142 ) 143 144 s.putQueuedPacket(queuedPacket) 145 continue 146 } 147 148 clientAddrPort, err := conn.SockaddrToAddrPort(msg.Msghdr.Name, msg.Msghdr.Namelen) 149 if err != nil { 150 s.logger.Warn("Failed to parse sockaddr of packet from serverConn", 151 zap.String("server", s.serverName), 152 zap.String("listenAddress", s.listenAddress), 153 zap.Error(err), 154 ) 155 156 s.putQueuedPacket(queuedPacket) 157 continue 158 } 159 160 err = conn.ParseFlagsForError(int(msg.Msghdr.Flags)) 161 if err != nil { 162 s.logger.Warn("Packet from serverConn discarded", 163 zap.String("server", s.serverName), 164 zap.String("listenAddress", s.listenAddress), 165 zap.Stringer("clientAddress", clientAddrPort), 166 zap.Uint32("packetLength", msg.Msglen), 167 zap.Error(err), 168 ) 169 170 s.putQueuedPacket(queuedPacket) 171 continue 172 } 173 174 var serverConnPacker zerocopy.ServerPacker 175 176 entry, ok := s.table[clientAddrPort] 177 if !ok { 178 entry = &natEntry{} 179 180 serverConnPacker, entry.serverConnUnpacker, err = s.server.NewSession() 181 if err != nil { 182 s.logger.Warn("Failed to create new session for serverConn", 183 zap.String("server", s.serverName), 184 zap.String("listenAddress", s.listenAddress), 185 zap.Stringer("clientAddress", clientAddrPort), 186 zap.Error(err), 187 ) 188 189 s.putQueuedPacket(queuedPacket) 190 continue 191 } 192 } 193 194 queuedPacket.targetAddr, queuedPacket.start, queuedPacket.length, err = entry.serverConnUnpacker.UnpackInPlace(queuedPacket.buf, clientAddrPort, s.packetBufFrontHeadroom, int(msg.Msglen)) 195 if err != nil { 196 s.logger.Warn("Failed to unpack packet from serverConn", 197 zap.String("server", s.serverName), 198 zap.String("listenAddress", s.listenAddress), 199 zap.Stringer("clientAddress", clientAddrPort), 200 zap.Uint32("packetLength", msg.Msglen), 201 zap.Error(err), 202 ) 203 204 s.putQueuedPacket(queuedPacket) 205 continue 206 } 207 208 payloadBytesReceived += uint64(queuedPacket.length) 209 210 var clientPktinfop *[]byte 211 cmsg := cmsgvec[i][:msg.Msghdr.Controllen] 212 213 if !bytes.Equal(entry.clientPktinfoCache, cmsg) { 214 clientPktinfoAddr, clientPktinfoIfindex, err := conn.ParsePktinfoCmsg(cmsg) 215 if err != nil { 216 s.logger.Warn("Failed to parse pktinfo control message from serverConn", 217 zap.String("server", s.serverName), 218 zap.String("listenAddress", s.listenAddress), 219 zap.Stringer("clientAddress", clientAddrPort), 220 zap.Stringer("targetAddress", &queuedPacket.targetAddr), 221 zap.Error(err), 222 ) 223 224 s.putQueuedPacket(queuedPacket) 225 continue 226 } 227 228 clientPktinfoCache := make([]byte, len(cmsg)) 229 copy(clientPktinfoCache, cmsg) 230 clientPktinfop = &clientPktinfoCache 231 entry.clientPktinfo.Store(clientPktinfop) 232 entry.clientPktinfoCache = clientPktinfoCache 233 234 if ce := s.logger.Check(zap.DebugLevel, "Updated client pktinfo"); ce != nil { 235 ce.Write( 236 zap.String("server", s.serverName), 237 zap.String("listenAddress", s.listenAddress), 238 zap.Stringer("clientAddress", clientAddrPort), 239 zap.Stringer("targetAddress", &queuedPacket.targetAddr), 240 zap.Stringer("clientPktinfoAddr", clientPktinfoAddr), 241 zap.Uint32("clientPktinfoIfindex", clientPktinfoIfindex), 242 ) 243 } 244 } 245 246 if !ok { 247 natConnSendCh := make(chan *natQueuedPacket, s.sendChannelCapacity) 248 entry.natConnSendCh = natConnSendCh 249 s.table[clientAddrPort] = entry 250 251 go func() { 252 var sendChClean bool 253 254 defer func() { 255 s.mu.Lock() 256 close(natConnSendCh) 257 delete(s.table, clientAddrPort) 258 s.mu.Unlock() 259 260 if !sendChClean { 261 for queuedPacket := range natConnSendCh { 262 s.putQueuedPacket(queuedPacket) 263 } 264 } 265 }() 266 267 c, err := s.router.GetUDPClient(router.RequestInfo{ 268 ServerIndex: s.serverIndex, 269 SourceAddrPort: clientAddrPort, 270 TargetAddr: queuedPacket.targetAddr, 271 }) 272 if err != nil { 273 s.logger.Warn("Failed to get UDP client for new NAT session", 274 zap.String("server", s.serverName), 275 zap.String("listenAddress", s.listenAddress), 276 zap.Stringer("clientAddress", clientAddrPort), 277 zap.Stringer("targetAddress", &queuedPacket.targetAddr), 278 zap.Error(err), 279 ) 280 return 281 } 282 283 // Only add for the current goroutine here, since we don't want the router to block exiting. 284 s.wg.Add(1) 285 defer s.wg.Done() 286 287 clientInfo, natConnPacker, natConnUnpacker, err := c.NewSession() 288 if err != nil { 289 s.logger.Warn("Failed to create new UDP client session", 290 zap.String("server", s.serverName), 291 zap.String("client", clientInfo.Name), 292 zap.String("listenAddress", s.listenAddress), 293 zap.Stringer("clientAddress", clientAddrPort), 294 zap.Stringer("targetAddress", &queuedPacket.targetAddr), 295 zap.Error(err), 296 ) 297 return 298 } 299 300 natConn, err := conn.ListenUDPRawConn(clientInfo.ListenConfig, "udp", "") 301 if err != nil { 302 s.logger.Warn("Failed to create UDP socket for new NAT session", 303 zap.String("server", s.serverName), 304 zap.String("client", clientInfo.Name), 305 zap.String("listenAddress", s.listenAddress), 306 zap.Stringer("clientAddress", clientAddrPort), 307 zap.Stringer("targetAddress", &queuedPacket.targetAddr), 308 zap.Error(err), 309 ) 310 return 311 } 312 313 err = natConn.SetReadDeadline(time.Now().Add(s.natTimeout)) 314 if err != nil { 315 s.logger.Warn("Failed to set read deadline on natConn", 316 zap.String("server", s.serverName), 317 zap.String("client", clientInfo.Name), 318 zap.String("listenAddress", s.listenAddress), 319 zap.Stringer("clientAddress", clientAddrPort), 320 zap.Stringer("targetAddress", &queuedPacket.targetAddr), 321 zap.Duration("natTimeout", s.natTimeout), 322 zap.Error(err), 323 ) 324 natConn.Close() 325 return 326 } 327 328 oldState := entry.state.Swap(natConn.UDPConn) 329 if oldState != nil { 330 natConn.Close() 331 return 332 } 333 334 // No more early returns! 335 sendChClean = true 336 337 s.logger.Info("UDP NAT relay started", 338 zap.String("server", s.serverName), 339 zap.String("client", clientInfo.Name), 340 zap.String("listenAddress", s.listenAddress), 341 zap.Stringer("clientAddress", clientAddrPort), 342 zap.Stringer("targetAddress", &queuedPacket.targetAddr), 343 ) 344 345 s.wg.Add(1) 346 347 go func() { 348 s.relayServerConnToNatConnSendmmsg(natUplinkMmsg{ 349 clientAddrPort: clientAddrPort, 350 natConn: natConn.WConn(), 351 natConnSendCh: natConnSendCh, 352 natConnPacker: natConnPacker, 353 }) 354 natConn.Close() 355 s.wg.Done() 356 }() 357 358 s.relayNatConnToServerConnSendmmsg(natDownlinkMmsg{ 359 clientAddrPort: clientAddrPort, 360 clientPktinfop: clientPktinfop, 361 clientPktinfo: &entry.clientPktinfo, 362 natConn: natConn.RConn(), 363 natConnRecvBufSize: clientInfo.MaxPacketSize, 364 natConnUnpacker: natConnUnpacker, 365 serverConn: serverConn.WConn(), 366 serverConnPacker: serverConnPacker, 367 }) 368 }() 369 370 if ce := s.logger.Check(zap.DebugLevel, "New UDP NAT session"); ce != nil { 371 ce.Write( 372 zap.String("server", s.serverName), 373 zap.String("listenAddress", s.listenAddress), 374 zap.Stringer("clientAddress", clientAddrPort), 375 zap.Stringer("targetAddress", &queuedPacket.targetAddr), 376 ) 377 } 378 } 379 380 select { 381 case entry.natConnSendCh <- queuedPacket: 382 default: 383 if ce := s.logger.Check(zap.DebugLevel, "Dropping packet due to full send channel"); ce != nil { 384 ce.Write( 385 zap.String("server", s.serverName), 386 zap.String("listenAddress", s.listenAddress), 387 zap.Stringer("clientAddress", clientAddrPort), 388 zap.Stringer("targetAddress", &queuedPacket.targetAddr), 389 ) 390 } 391 392 s.putQueuedPacket(queuedPacket) 393 } 394 } 395 396 s.mu.Unlock() 397 } 398 399 for i := range qpvec { 400 s.putQueuedPacket(qpvec[i]) 401 } 402 403 s.logger.Info("Finished receiving from serverConn", 404 zap.String("server", s.serverName), 405 zap.String("listenAddress", s.listenAddress), 406 zap.Uint64("recvmmsgCount", recvmmsgCount), 407 zap.Uint64("packetsReceived", packetsReceived), 408 zap.Uint64("payloadBytesReceived", payloadBytesReceived), 409 zap.Int("burstBatchSize", burstBatchSize), 410 ) 411 } 412 413 func (s *UDPNATRelay) relayServerConnToNatConnSendmmsg(uplink natUplinkMmsg) { 414 var ( 415 destAddrPort netip.AddrPort 416 packetStart int 417 packetLength int 418 err error 419 sendmmsgCount uint64 420 packetsSent uint64 421 payloadBytesSent uint64 422 burstBatchSize int 423 ) 424 425 qpvec := make([]*natQueuedPacket, s.relayBatchSize) 426 namevec := make([]unix.RawSockaddrInet6, s.relayBatchSize) 427 iovec := make([]unix.Iovec, s.relayBatchSize) 428 msgvec := make([]conn.Mmsghdr, s.relayBatchSize) 429 430 for i := range msgvec { 431 msgvec[i].Msghdr.Name = (*byte)(unsafe.Pointer(&namevec[i])) 432 msgvec[i].Msghdr.Namelen = unix.SizeofSockaddrInet6 433 msgvec[i].Msghdr.Iov = &iovec[i] 434 msgvec[i].Msghdr.SetIovlen(1) 435 } 436 437 main: 438 for { 439 var count int 440 441 // Block on first dequeue op. 442 queuedPacket, ok := <-uplink.natConnSendCh 443 if !ok { 444 break 445 } 446 447 dequeue: 448 for { 449 destAddrPort, packetStart, packetLength, err = uplink.natConnPacker.PackInPlace(queuedPacket.buf, queuedPacket.targetAddr, queuedPacket.start, queuedPacket.length) 450 if err != nil { 451 s.logger.Warn("Failed to pack packet for natConn", 452 zap.String("server", s.serverName), 453 zap.String("listenAddress", s.listenAddress), 454 zap.Stringer("clientAddress", uplink.clientAddrPort), 455 zap.Stringer("targetAddress", &queuedPacket.targetAddr), 456 zap.Int("payloadLength", queuedPacket.length), 457 zap.Error(err), 458 ) 459 460 s.putQueuedPacket(queuedPacket) 461 462 if count == 0 { 463 continue main 464 } 465 goto next 466 } 467 468 qpvec[count] = queuedPacket 469 namevec[count] = conn.AddrPortToSockaddrInet6(destAddrPort) 470 iovec[count].Base = &queuedPacket.buf[packetStart] 471 iovec[count].SetLen(packetLength) 472 count++ 473 payloadBytesSent += uint64(queuedPacket.length) 474 475 if count == s.relayBatchSize { 476 break 477 } 478 479 next: 480 select { 481 case queuedPacket, ok = <-uplink.natConnSendCh: 482 if !ok { 483 break dequeue 484 } 485 default: 486 break dequeue 487 } 488 } 489 490 if err := uplink.natConn.WriteMsgs(msgvec[:count], 0); err != nil { 491 s.logger.Warn("Failed to batch write packets to natConn", 492 zap.String("server", s.serverName), 493 zap.String("listenAddress", s.listenAddress), 494 zap.Stringer("clientAddress", uplink.clientAddrPort), 495 zap.Stringer("lastTargetAddress", &qpvec[count-1].targetAddr), 496 zap.Stringer("lastWriteDestAddress", destAddrPort), 497 zap.Error(err), 498 ) 499 } 500 501 if err := uplink.natConn.SetReadDeadline(time.Now().Add(s.natTimeout)); err != nil { 502 s.logger.Warn("Failed to set read deadline on natConn", 503 zap.String("server", s.serverName), 504 zap.String("listenAddress", s.listenAddress), 505 zap.Stringer("clientAddress", uplink.clientAddrPort), 506 zap.Duration("natTimeout", s.natTimeout), 507 zap.Error(err), 508 ) 509 } 510 511 sendmmsgCount++ 512 packetsSent += uint64(count) 513 if burstBatchSize < count { 514 burstBatchSize = count 515 } 516 517 qpvecn := qpvec[:count] 518 519 for i := range qpvecn { 520 s.putQueuedPacket(qpvecn[i]) 521 } 522 523 if !ok { 524 break 525 } 526 } 527 528 s.logger.Info("Finished relay serverConn -> natConn", 529 zap.String("server", s.serverName), 530 zap.String("listenAddress", s.listenAddress), 531 zap.Stringer("clientAddress", uplink.clientAddrPort), 532 zap.Stringer("lastWriteDestAddress", destAddrPort), 533 zap.Uint64("sendmmsgCount", sendmmsgCount), 534 zap.Uint64("packetsSent", packetsSent), 535 zap.Uint64("payloadBytesSent", payloadBytesSent), 536 zap.Int("burstBatchSize", burstBatchSize), 537 ) 538 539 s.collector.CollectUDPSessionUplink("", packetsSent, payloadBytesSent) 540 } 541 542 func (s *UDPNATRelay) relayNatConnToServerConnSendmmsg(downlink natDownlinkMmsg) { 543 clientPktinfop := downlink.clientPktinfop 544 clientPktinfo := *clientPktinfop 545 maxClientPacketSize := zerocopy.MaxPacketSizeForAddr(s.mtu, downlink.clientAddrPort.Addr()) 546 547 serverConnPackerInfo := downlink.serverConnPacker.ServerPackerInfo() 548 natConnUnpackerInfo := downlink.natConnUnpacker.ClientUnpackerInfo() 549 headroom := zerocopy.UDPRelayHeadroom(serverConnPackerInfo.Headroom, natConnUnpackerInfo.Headroom) 550 551 var ( 552 sendmmsgCount uint64 553 packetsSent uint64 554 payloadBytesSent uint64 555 burstBatchSize int 556 ) 557 558 name, namelen := conn.AddrPortToSockaddr(downlink.clientAddrPort) 559 savec := make([]unix.RawSockaddrInet6, s.relayBatchSize) 560 bufvec := make([][]byte, s.relayBatchSize) 561 riovec := make([]unix.Iovec, s.relayBatchSize) 562 siovec := make([]unix.Iovec, s.relayBatchSize) 563 rmsgvec := make([]conn.Mmsghdr, s.relayBatchSize) 564 smsgvec := make([]conn.Mmsghdr, s.relayBatchSize) 565 566 for i := 0; i < s.relayBatchSize; i++ { 567 packetBuf := make([]byte, headroom.Front+downlink.natConnRecvBufSize+headroom.Rear) 568 bufvec[i] = packetBuf 569 570 riovec[i].Base = &packetBuf[headroom.Front] 571 riovec[i].SetLen(downlink.natConnRecvBufSize) 572 573 rmsgvec[i].Msghdr.Name = (*byte)(unsafe.Pointer(&savec[i])) 574 rmsgvec[i].Msghdr.Namelen = unix.SizeofSockaddrInet6 575 rmsgvec[i].Msghdr.Iov = &riovec[i] 576 rmsgvec[i].Msghdr.SetIovlen(1) 577 578 smsgvec[i].Msghdr.Name = name 579 smsgvec[i].Msghdr.Namelen = namelen 580 smsgvec[i].Msghdr.Iov = &siovec[i] 581 smsgvec[i].Msghdr.SetIovlen(1) 582 smsgvec[i].Msghdr.Control = &clientPktinfo[0] 583 smsgvec[i].Msghdr.SetControllen(len(clientPktinfo)) 584 } 585 586 for { 587 nr, err := downlink.natConn.ReadMsgs(rmsgvec, 0) 588 if err != nil { 589 if errors.Is(err, os.ErrDeadlineExceeded) { 590 break 591 } 592 593 s.logger.Warn("Failed to batch read packets from natConn", 594 zap.String("server", s.serverName), 595 zap.String("listenAddress", s.listenAddress), 596 zap.Stringer("clientAddress", downlink.clientAddrPort), 597 zap.Error(err), 598 ) 599 continue 600 } 601 602 var ns int 603 rmsgvecn := rmsgvec[:nr] 604 605 for i := range rmsgvecn { 606 msg := &rmsgvecn[i] 607 608 packetSourceAddrPort, err := conn.SockaddrToAddrPort(msg.Msghdr.Name, msg.Msghdr.Namelen) 609 if err != nil { 610 s.logger.Warn("Failed to parse sockaddr of packet from natConn", 611 zap.String("server", s.serverName), 612 zap.String("listenAddress", s.listenAddress), 613 zap.Stringer("clientAddress", downlink.clientAddrPort), 614 zap.Error(err), 615 ) 616 continue 617 } 618 619 err = conn.ParseFlagsForError(int(msg.Msghdr.Flags)) 620 if err != nil { 621 s.logger.Warn("Packet from natConn discarded", 622 zap.String("server", s.serverName), 623 zap.String("listenAddress", s.listenAddress), 624 zap.Stringer("clientAddress", downlink.clientAddrPort), 625 zap.Stringer("packetSourceAddress", packetSourceAddrPort), 626 zap.Uint32("packetLength", msg.Msglen), 627 zap.Error(err), 628 ) 629 continue 630 } 631 632 packetBuf := bufvec[i] 633 634 payloadSourceAddrPort, payloadStart, payloadLength, err := downlink.natConnUnpacker.UnpackInPlace(packetBuf, packetSourceAddrPort, headroom.Front, int(msg.Msglen)) 635 if err != nil { 636 s.logger.Warn("Failed to unpack packet from natConn", 637 zap.String("server", s.serverName), 638 zap.String("listenAddress", s.listenAddress), 639 zap.Stringer("clientAddress", downlink.clientAddrPort), 640 zap.Stringer("packetSourceAddress", packetSourceAddrPort), 641 zap.Uint32("packetLength", msg.Msglen), 642 zap.Error(err), 643 ) 644 continue 645 } 646 647 packetStart, packetLength, err := downlink.serverConnPacker.PackInPlace(packetBuf, payloadSourceAddrPort, payloadStart, payloadLength, maxClientPacketSize) 648 if err != nil { 649 s.logger.Warn("Failed to pack packet for serverConn", 650 zap.String("server", s.serverName), 651 zap.String("listenAddress", s.listenAddress), 652 zap.Stringer("clientAddress", downlink.clientAddrPort), 653 zap.Stringer("packetSourceAddress", packetSourceAddrPort), 654 zap.Stringer("payloadSourceAddress", payloadSourceAddrPort), 655 zap.Int("payloadLength", payloadLength), 656 zap.Int("maxClientPacketSize", maxClientPacketSize), 657 zap.Error(err), 658 ) 659 continue 660 } 661 662 siovec[ns].Base = &packetBuf[packetStart] 663 siovec[ns].SetLen(packetLength) 664 ns++ 665 payloadBytesSent += uint64(payloadLength) 666 } 667 668 if ns == 0 { 669 continue 670 } 671 672 if cpp := downlink.clientPktinfo.Load(); cpp != clientPktinfop { 673 clientPktinfo = *cpp 674 clientPktinfop = cpp 675 676 for i := range smsgvec { 677 smsgvec[i].Msghdr.Control = &clientPktinfo[0] 678 smsgvec[i].Msghdr.SetControllen(len(clientPktinfo)) 679 } 680 } 681 682 err = downlink.serverConn.WriteMsgs(smsgvec[:ns], 0) 683 if err != nil { 684 s.logger.Warn("Failed to batch write packets to serverConn", 685 zap.String("server", s.serverName), 686 zap.String("listenAddress", s.listenAddress), 687 zap.Stringer("clientAddress", downlink.clientAddrPort), 688 zap.Error(err), 689 ) 690 } 691 692 sendmmsgCount++ 693 packetsSent += uint64(ns) 694 if burstBatchSize < ns { 695 burstBatchSize = ns 696 } 697 } 698 699 s.logger.Info("Finished relay serverConn <- natConn", 700 zap.String("server", s.serverName), 701 zap.String("listenAddress", s.listenAddress), 702 zap.Stringer("clientAddress", downlink.clientAddrPort), 703 zap.Uint64("sendmmsgCount", sendmmsgCount), 704 zap.Uint64("packetsSent", packetsSent), 705 zap.Uint64("payloadBytesSent", payloadBytesSent), 706 zap.Int("burstBatchSize", burstBatchSize), 707 ) 708 709 s.collector.CollectUDPSessionDownlink("", packetsSent, payloadBytesSent) 710 }