1
0

client.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package v2rayquic
  2. import (
  3. "context"
  4. "net"
  5. "sync"
  6. "github.com/sagernet/quic-go"
  7. "github.com/sagernet/sing-box/adapter"
  8. "github.com/sagernet/sing-box/common/tls"
  9. C "github.com/sagernet/sing-box/constant"
  10. "github.com/sagernet/sing-box/option"
  11. "github.com/sagernet/sing-box/transport/hysteria"
  12. "github.com/sagernet/sing/common"
  13. "github.com/sagernet/sing/common/bufio"
  14. M "github.com/sagernet/sing/common/metadata"
  15. N "github.com/sagernet/sing/common/network"
  16. )
  17. var _ adapter.V2RayClientTransport = (*Client)(nil)
  18. type Client struct {
  19. ctx context.Context
  20. dialer N.Dialer
  21. serverAddr M.Socksaddr
  22. tlsConfig *tls.STDConfig
  23. quicConfig *quic.Config
  24. connAccess sync.Mutex
  25. conn quic.Connection
  26. rawConn net.Conn
  27. }
  28. func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayQUICOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) {
  29. quicConfig := &quic.Config{
  30. DisablePathMTUDiscovery: !C.IsLinux && !C.IsWindows,
  31. }
  32. stdConfig, err := tlsConfig.Config()
  33. if err != nil {
  34. return nil, err
  35. }
  36. if len(stdConfig.NextProtos) == 0 {
  37. stdConfig.NextProtos = []string{"h2", "http/1.1"}
  38. }
  39. return &Client{
  40. ctx: ctx,
  41. dialer: dialer,
  42. serverAddr: serverAddr,
  43. tlsConfig: stdConfig,
  44. quicConfig: quicConfig,
  45. }, nil
  46. }
  47. func (c *Client) offer() (quic.Connection, error) {
  48. conn := c.conn
  49. if conn != nil && !common.Done(conn.Context()) {
  50. return conn, nil
  51. }
  52. c.connAccess.Lock()
  53. defer c.connAccess.Unlock()
  54. conn = c.conn
  55. if conn != nil && !common.Done(conn.Context()) {
  56. return conn, nil
  57. }
  58. conn, err := c.offerNew()
  59. if err != nil {
  60. return nil, err
  61. }
  62. return conn, nil
  63. }
  64. func (c *Client) offerNew() (quic.Connection, error) {
  65. udpConn, err := c.dialer.DialContext(c.ctx, "udp", c.serverAddr)
  66. if err != nil {
  67. return nil, err
  68. }
  69. var packetConn net.PacketConn
  70. packetConn = bufio.NewUnbindPacketConn(udpConn)
  71. quicConn, err := quic.Dial(packetConn, udpConn.RemoteAddr(), c.serverAddr.AddrString(), c.tlsConfig, c.quicConfig)
  72. if err != nil {
  73. packetConn.Close()
  74. return nil, err
  75. }
  76. c.conn = quicConn
  77. c.rawConn = udpConn
  78. return quicConn, nil
  79. }
  80. func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
  81. conn, err := c.offer()
  82. if err != nil {
  83. return nil, err
  84. }
  85. stream, err := conn.OpenStream()
  86. if err != nil {
  87. return nil, err
  88. }
  89. return &hysteria.StreamWrapper{Conn: conn, Stream: stream}, nil
  90. }
  91. func (c *Client) Close() error {
  92. return common.Close(c.conn, c.rawConn)
  93. }