| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 | 
							- package tf
 
- import (
 
- 	"context"
 
- 	"net"
 
- 	"time"
 
- 	"github.com/sagernet/sing/common/control"
 
- 	"golang.org/x/sys/unix"
 
- )
 
- /*
 
- const tcpMaxNotifyAck = 10
 
- type tcpNotifyAckID uint32
 
- 	type tcpNotifyAckComplete struct {
 
- 		NotifyPending       uint32
 
- 		NotifyCompleteCount uint32
 
- 		NotifyCompleteID    [tcpMaxNotifyAck]tcpNotifyAckID
 
- 	}
 
- var sizeOfTCPNotifyAckComplete = int(unsafe.Sizeof(tcpNotifyAckComplete{}))
 
- 	func getsockoptTCPNotifyAckComplete(fd, level, opt int) (*tcpNotifyAckComplete, error) {
 
- 		var value tcpNotifyAckComplete
 
- 		vallen := uint32(sizeOfTCPNotifyAckComplete)
 
- 		err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
 
- 		return &value, err
 
- 	}
 
- //go:linkname getsockopt golang.org/x/sys/unix.getsockopt
 
- func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *uint32) error
 
- 	func waitAck(ctx context.Context, conn *net.TCPConn, _ time.Duration) error {
 
- 		const TCP_NOTIFY_ACKNOWLEDGEMENT = 0x212
 
- 		return control.Conn(conn, func(fd uintptr) error {
 
- 			err := unix.SetsockoptInt(int(fd), unix.IPPROTO_TCP, TCP_NOTIFY_ACKNOWLEDGEMENT, 1)
 
- 			if err != nil {
 
- 				if errors.Is(err, unix.EINVAL) {
 
- 					return waitAckFallback(ctx, conn, 0)
 
- 				}
 
- 				return err
 
- 			}
 
- 			for {
 
- 				select {
 
- 				case <-ctx.Done():
 
- 					return ctx.Err()
 
- 				default:
 
- 				}
 
- 				var ackComplete *tcpNotifyAckComplete
 
- 				ackComplete, err = getsockoptTCPNotifyAckComplete(int(fd), unix.IPPROTO_TCP, TCP_NOTIFY_ACKNOWLEDGEMENT)
 
- 				if err != nil {
 
- 					return err
 
- 				}
 
- 				if ackComplete.NotifyPending == 0 {
 
- 					return nil
 
- 				}
 
- 				time.Sleep(10 * time.Millisecond)
 
- 			}
 
- 		})
 
- 	}
 
- */
 
- func writeAndWaitAck(ctx context.Context, conn *net.TCPConn, payload []byte, fallbackDelay time.Duration) error {
 
- 	_, err := conn.Write(payload)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	return control.Conn(conn, func(fd uintptr) error {
 
- 		start := time.Now()
 
- 		for {
 
- 			select {
 
- 			case <-ctx.Done():
 
- 				return ctx.Err()
 
- 			default:
 
- 			}
 
- 			unacked, err := unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_NWRITE)
 
- 			if err != nil {
 
- 				return err
 
- 			}
 
- 			if unacked == 0 {
 
- 				if time.Since(start) <= 20*time.Millisecond {
 
- 					// under transparent proxy
 
- 					time.Sleep(fallbackDelay)
 
- 				}
 
- 				return nil
 
- 			}
 
- 			time.Sleep(10 * time.Millisecond)
 
- 		}
 
- 	})
 
- }
 
 
  |