quic_misc.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // Copyright (C) 2019 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at http://mozilla.org/MPL/2.0/.
  6. //go:build !noquic
  7. // +build !noquic
  8. package connections
  9. import (
  10. "context"
  11. "crypto/tls"
  12. "net"
  13. "net/url"
  14. "sync/atomic"
  15. "time"
  16. "github.com/quic-go/quic-go"
  17. "github.com/quic-go/quic-go/logging"
  18. "github.com/syncthing/syncthing/lib/osutil"
  19. )
  20. var quicConfig = &quic.Config{
  21. MaxIdleTimeout: 30 * time.Second,
  22. KeepAlivePeriod: 15 * time.Second,
  23. }
  24. func quicNetwork(uri *url.URL) string {
  25. switch uri.Scheme {
  26. case "quic4":
  27. return "udp4"
  28. case "quic6":
  29. return "udp6"
  30. default:
  31. return "udp"
  32. }
  33. }
  34. type quicTlsConn struct {
  35. quic.Connection
  36. quic.Stream
  37. // If we created this connection, we should be the ones closing it.
  38. createdConn net.PacketConn
  39. }
  40. func (q *quicTlsConn) Close() error {
  41. sterr := q.Stream.Close()
  42. seerr := q.Connection.CloseWithError(0, "closing")
  43. var pcerr error
  44. if q.createdConn != nil {
  45. pcerr = q.createdConn.Close()
  46. }
  47. if sterr != nil {
  48. return sterr
  49. }
  50. if seerr != nil {
  51. return seerr
  52. }
  53. return pcerr
  54. }
  55. func (q *quicTlsConn) ConnectionState() tls.ConnectionState {
  56. return q.Connection.ConnectionState().TLS
  57. }
  58. func transportConnUnspecified(conn any) bool {
  59. tran, ok := conn.(*quic.Transport)
  60. if !ok {
  61. return false
  62. }
  63. addr := tran.Conn.LocalAddr()
  64. ip, err := osutil.IPFromAddr(addr)
  65. return err == nil && ip.IsUnspecified()
  66. }
  67. type writeTrackingTracer struct {
  68. lastWrite atomic.Int64 // unix nanos
  69. }
  70. func (t *writeTrackingTracer) loggingTracer() *logging.Tracer {
  71. return &logging.Tracer{
  72. SentPacket: func(net.Addr, *logging.Header, logging.ByteCount, []logging.Frame) {
  73. t.lastWrite.Store(time.Now().UnixNano())
  74. },
  75. SentVersionNegotiationPacket: func(net.Addr, logging.ArbitraryLenConnectionID, logging.ArbitraryLenConnectionID, []logging.Version) {
  76. t.lastWrite.Store(time.Now().UnixNano())
  77. },
  78. }
  79. }
  80. func (t *writeTrackingTracer) LastWrite() time.Time {
  81. return time.Unix(0, t.lastWrite.Load())
  82. }
  83. // A transportPacketConn is a net.PacketConn that uses a quic.Transport.
  84. type transportPacketConn struct {
  85. tran *quic.Transport
  86. readDeadline atomic.Value // time.Time
  87. }
  88. func (t *transportPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
  89. ctx := context.Background()
  90. if deadline, ok := t.readDeadline.Load().(time.Time); ok && !deadline.IsZero() {
  91. var cancel context.CancelFunc
  92. ctx, cancel = context.WithDeadline(ctx, deadline)
  93. defer cancel()
  94. }
  95. return t.tran.ReadNonQUICPacket(ctx, p)
  96. }
  97. func (t *transportPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
  98. return t.tran.WriteTo(p, addr)
  99. }
  100. func (*transportPacketConn) Close() error {
  101. return errUnsupported
  102. }
  103. func (t *transportPacketConn) LocalAddr() net.Addr {
  104. return t.tran.Conn.LocalAddr()
  105. }
  106. func (t *transportPacketConn) SetDeadline(deadline time.Time) error {
  107. return t.SetReadDeadline(deadline)
  108. }
  109. func (t *transportPacketConn) SetReadDeadline(deadline time.Time) error {
  110. t.readDeadline.Store(deadline)
  111. return nil
  112. }
  113. func (*transportPacketConn) SetWriteDeadline(_ time.Time) error {
  114. return nil // yolo
  115. }