closed_session.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. package quic
  2. import (
  3. "sync"
  4. "github.com/Psiphon-Labs/quic-go/internal/protocol"
  5. "github.com/Psiphon-Labs/quic-go/internal/utils"
  6. )
  7. // A closedLocalSession is a session that we closed locally.
  8. // When receiving packets for such a session, we need to retransmit the packet containing the CONNECTION_CLOSE frame,
  9. // with an exponential backoff.
  10. type closedLocalSession struct {
  11. conn sendConn
  12. connClosePacket []byte
  13. closeOnce sync.Once
  14. closeChan chan struct{} // is closed when the session is closed or destroyed
  15. receivedPackets chan *receivedPacket
  16. counter uint64 // number of packets received
  17. perspective protocol.Perspective
  18. logger utils.Logger
  19. }
  20. var _ packetHandler = &closedLocalSession{}
  21. // newClosedLocalSession creates a new closedLocalSession and runs it.
  22. func newClosedLocalSession(
  23. conn sendConn,
  24. connClosePacket []byte,
  25. perspective protocol.Perspective,
  26. logger utils.Logger,
  27. ) packetHandler {
  28. s := &closedLocalSession{
  29. conn: conn,
  30. connClosePacket: connClosePacket,
  31. perspective: perspective,
  32. logger: logger,
  33. closeChan: make(chan struct{}),
  34. receivedPackets: make(chan *receivedPacket, 64),
  35. }
  36. go s.run()
  37. return s
  38. }
  39. func (s *closedLocalSession) run() {
  40. for {
  41. select {
  42. case p := <-s.receivedPackets:
  43. s.handlePacketImpl(p)
  44. case <-s.closeChan:
  45. return
  46. }
  47. }
  48. }
  49. func (s *closedLocalSession) handlePacket(p *receivedPacket) {
  50. select {
  51. case s.receivedPackets <- p:
  52. default:
  53. }
  54. }
  55. func (s *closedLocalSession) handlePacketImpl(_ *receivedPacket) {
  56. s.counter++
  57. // exponential backoff
  58. // only send a CONNECTION_CLOSE for the 1st, 2nd, 4th, 8th, 16th, ... packet arriving
  59. for n := s.counter; n > 1; n = n / 2 {
  60. if n%2 != 0 {
  61. return
  62. }
  63. }
  64. s.logger.Debugf("Received %d packets after sending CONNECTION_CLOSE. Retransmitting.", s.counter)
  65. if err := s.conn.Write(s.connClosePacket); err != nil {
  66. s.logger.Debugf("Error retransmitting CONNECTION_CLOSE: %s", err)
  67. }
  68. }
  69. func (s *closedLocalSession) shutdown() {
  70. s.destroy(nil)
  71. }
  72. func (s *closedLocalSession) destroy(error) {
  73. s.closeOnce.Do(func() {
  74. close(s.closeChan)
  75. })
  76. }
  77. func (s *closedLocalSession) getPerspective() protocol.Perspective {
  78. return s.perspective
  79. }
  80. // A closedRemoteSession is a session that was closed remotely.
  81. // For such a session, we might receive reordered packets that were sent before the CONNECTION_CLOSE.
  82. // We can just ignore those packets.
  83. type closedRemoteSession struct {
  84. perspective protocol.Perspective
  85. }
  86. var _ packetHandler = &closedRemoteSession{}
  87. func newClosedRemoteSession(pers protocol.Perspective) packetHandler {
  88. return &closedRemoteSession{perspective: pers}
  89. }
  90. func (s *closedRemoteSession) handlePacket(*receivedPacket) {}
  91. func (s *closedRemoteSession) shutdown() {}
  92. func (s *closedRemoteSession) destroy(error) {}
  93. func (s *closedRemoteSession) getPerspective() protocol.Perspective { return s.perspective }