wait_darwin.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package tf
  2. import (
  3. "context"
  4. "net"
  5. "time"
  6. "github.com/sagernet/sing/common/control"
  7. "golang.org/x/sys/unix"
  8. )
  9. /*
  10. const tcpMaxNotifyAck = 10
  11. type tcpNotifyAckID uint32
  12. type tcpNotifyAckComplete struct {
  13. NotifyPending uint32
  14. NotifyCompleteCount uint32
  15. NotifyCompleteID [tcpMaxNotifyAck]tcpNotifyAckID
  16. }
  17. var sizeOfTCPNotifyAckComplete = int(unsafe.Sizeof(tcpNotifyAckComplete{}))
  18. func getsockoptTCPNotifyAckComplete(fd, level, opt int) (*tcpNotifyAckComplete, error) {
  19. var value tcpNotifyAckComplete
  20. vallen := uint32(sizeOfTCPNotifyAckComplete)
  21. err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
  22. return &value, err
  23. }
  24. //go:linkname getsockopt golang.org/x/sys/unix.getsockopt
  25. func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *uint32) error
  26. func waitAck(ctx context.Context, conn *net.TCPConn, _ time.Duration) error {
  27. const TCP_NOTIFY_ACKNOWLEDGEMENT = 0x212
  28. return control.Conn(conn, func(fd uintptr) error {
  29. err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, TCP_NOTIFY_ACKNOWLEDGEMENT, 1)
  30. if err != nil {
  31. if errors.Is(err, unix.EINVAL) {
  32. return waitAckFallback(ctx, conn, 0)
  33. }
  34. return err
  35. }
  36. for {
  37. select {
  38. case <-ctx.Done():
  39. return ctx.Err()
  40. default:
  41. }
  42. var ackComplete *tcpNotifyAckComplete
  43. ackComplete, err = getsockoptTCPNotifyAckComplete(int(fd), unix.IPPROTO_TCP, TCP_NOTIFY_ACKNOWLEDGEMENT)
  44. if err != nil {
  45. return err
  46. }
  47. if ackComplete.NotifyPending == 0 {
  48. return nil
  49. }
  50. time.Sleep(10 * time.Millisecond)
  51. }
  52. })
  53. }
  54. */
  55. func writeAndWaitAck(ctx context.Context, conn *net.TCPConn, payload []byte, fallbackDelay time.Duration) error {
  56. _, err := conn.Write(payload)
  57. if err != nil {
  58. return err
  59. }
  60. return control.Conn(conn, func(fd uintptr) error {
  61. start := time.Now()
  62. for {
  63. select {
  64. case <-ctx.Done():
  65. return ctx.Err()
  66. default:
  67. }
  68. unacked, err := unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_NWRITE)
  69. if err != nil {
  70. return err
  71. }
  72. if unacked == 0 {
  73. if time.Since(start) <= 20*time.Millisecond {
  74. // under transparent proxy
  75. time.Sleep(fallbackDelay)
  76. }
  77. return nil
  78. }
  79. time.Sleep(10 * time.Millisecond)
  80. }
  81. })
  82. }