Highly-opinionated (ex-bullshit-free) MTPROTO proxy for Telegram. If you use v1.0 or upgrade broke you proxy, please read the chapter Version 2
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

sockopts_test.go 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. //go:build linux || darwin
  2. // +build linux darwin
  3. package network
  4. import (
  5. "net"
  6. "runtime"
  7. "syscall"
  8. "testing"
  9. "time"
  10. "github.com/stretchr/testify/require"
  11. "golang.org/x/sys/unix"
  12. )
  13. func tcpKeepIdleOption() int {
  14. if runtime.GOOS == "darwin" {
  15. return 0x10 // TCP_KEEPALIVE on macOS
  16. }
  17. return 0x4 // TCP_KEEPIDLE on Linux
  18. }
  19. func TestSetCommonSocketOptionsKeepAlive(t *testing.T) {
  20. t.Parallel()
  21. listener, err := net.Listen("tcp", "127.0.0.1:0")
  22. require.NoError(t, err)
  23. defer func() {
  24. err := listener.Close()
  25. require.NoError(t, err)
  26. }()
  27. type dialResult struct {
  28. conn net.Conn
  29. err error
  30. }
  31. dialDone := make(chan dialResult, 1)
  32. go func() {
  33. c, err := net.Dial("tcp", listener.Addr().String())
  34. dialDone <- dialResult{conn: c, err: err}
  35. }()
  36. tcpListener, ok := listener.(*net.TCPListener)
  37. require.True(t, ok, "listener must be a *net.TCPListener")
  38. require.NoError(t, tcpListener.SetDeadline(time.Now().Add(5*time.Second)))
  39. accepted, err := listener.Accept()
  40. require.NoError(t, err)
  41. defer func() {
  42. err := accepted.Close()
  43. require.NoError(t, err)
  44. }()
  45. dr := <-dialDone
  46. require.NoError(t, dr.err)
  47. defer func() {
  48. err := dr.conn.Close()
  49. require.NoError(t, err)
  50. }()
  51. tcpConn := accepted.(*net.TCPConn)
  52. err = setCommonSocketOptions(tcpConn, DefaultKeepAliveConfig, DefaultTCPNotSentLowat)
  53. require.NoError(t, err)
  54. rawConn, err := tcpConn.SyscallConn()
  55. require.NoError(t, err)
  56. err = rawConn.Control(func(fd uintptr) {
  57. val, err := unix.GetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE)
  58. require.NoError(t, err)
  59. require.NotEqual(t, 0, val, "SO_KEEPALIVE should be enabled")
  60. idle, err := unix.GetsockoptInt(int(fd), syscall.IPPROTO_TCP, tcpKeepIdleOption())
  61. require.NoError(t, err)
  62. require.Equal(t, 15, idle, "keepalive idle should match DefaultKeepAliveIdle")
  63. interval, err := unix.GetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_KEEPINTVL)
  64. require.NoError(t, err)
  65. require.Equal(t, 15, interval, "keepalive interval should match DefaultKeepAliveInterval")
  66. count, err := unix.GetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_KEEPCNT)
  67. require.NoError(t, err)
  68. require.Equal(t, 9, count, "keepalive count should match DefaultKeepAliveCount")
  69. })
  70. require.NoError(t, err)
  71. }
  72. func TestSetCommonSocketOptionsNotSentLowat(t *testing.T) {
  73. t.Parallel()
  74. cases := []struct {
  75. name string
  76. want int
  77. }{
  78. {name: "default", want: DefaultTCPNotSentLowat},
  79. {name: "custom", want: 4 * 1024 * 1024},
  80. }
  81. for _, tc := range cases {
  82. t.Run(tc.name, func(t *testing.T) {
  83. t.Parallel()
  84. listener, err := net.Listen("tcp", "127.0.0.1:0")
  85. require.NoError(t, err)
  86. defer listener.Close() //nolint: errcheck
  87. dialDone := make(chan struct{})
  88. go func() {
  89. c, err := net.Dial("tcp", listener.Addr().String())
  90. if err == nil {
  91. defer c.Close() //nolint: errcheck
  92. }
  93. close(dialDone)
  94. }()
  95. require.NoError(t, listener.(*net.TCPListener).SetDeadline(time.Now().Add(5*time.Second)))
  96. accepted, err := listener.Accept()
  97. require.NoError(t, err)
  98. defer accepted.Close() //nolint: errcheck
  99. <-dialDone
  100. tcpConn := accepted.(*net.TCPConn)
  101. require.NoError(t, setCommonSocketOptions(tcpConn, DefaultKeepAliveConfig, tc.want))
  102. rawConn, err := tcpConn.SyscallConn()
  103. require.NoError(t, err)
  104. err = rawConn.Control(func(fd uintptr) {
  105. got, err := unix.GetsockoptInt(int(fd), unix.IPPROTO_TCP, unix.TCP_NOTSENT_LOWAT)
  106. require.NoError(t, err)
  107. require.Equal(t, tc.want, got, "TCP_NOTSENT_LOWAT should match value passed to setCommonSocketOptions")
  108. })
  109. require.NoError(t, err)
  110. })
  111. }
  112. }