| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- package quic
- import (
- "sync"
- "github.com/Psiphon-Labs/quic-go/internal/protocol"
- "github.com/Psiphon-Labs/quic-go/internal/utils"
- )
- // A closedLocalSession is a session that we closed locally.
- // When receiving packets for such a session, we need to retransmit the packet containing the CONNECTION_CLOSE frame,
- // with an exponential backoff.
- type closedLocalSession struct {
- conn sendConn
- connClosePacket []byte
- closeOnce sync.Once
- closeChan chan struct{} // is closed when the session is closed or destroyed
- receivedPackets chan *receivedPacket
- counter uint64 // number of packets received
- perspective protocol.Perspective
- logger utils.Logger
- }
- var _ packetHandler = &closedLocalSession{}
- // newClosedLocalSession creates a new closedLocalSession and runs it.
- func newClosedLocalSession(
- conn sendConn,
- connClosePacket []byte,
- perspective protocol.Perspective,
- logger utils.Logger,
- ) packetHandler {
- s := &closedLocalSession{
- conn: conn,
- connClosePacket: connClosePacket,
- perspective: perspective,
- logger: logger,
- closeChan: make(chan struct{}),
- receivedPackets: make(chan *receivedPacket, 64),
- }
- go s.run()
- return s
- }
- func (s *closedLocalSession) run() {
- for {
- select {
- case p := <-s.receivedPackets:
- s.handlePacketImpl(p)
- case <-s.closeChan:
- return
- }
- }
- }
- func (s *closedLocalSession) handlePacket(p *receivedPacket) {
- select {
- case s.receivedPackets <- p:
- default:
- }
- }
- func (s *closedLocalSession) handlePacketImpl(_ *receivedPacket) {
- s.counter++
- // exponential backoff
- // only send a CONNECTION_CLOSE for the 1st, 2nd, 4th, 8th, 16th, ... packet arriving
- for n := s.counter; n > 1; n = n / 2 {
- if n%2 != 0 {
- return
- }
- }
- s.logger.Debugf("Received %d packets after sending CONNECTION_CLOSE. Retransmitting.", s.counter)
- if err := s.conn.Write(s.connClosePacket); err != nil {
- s.logger.Debugf("Error retransmitting CONNECTION_CLOSE: %s", err)
- }
- }
- func (s *closedLocalSession) shutdown() {
- s.destroy(nil)
- }
- func (s *closedLocalSession) destroy(error) {
- s.closeOnce.Do(func() {
- close(s.closeChan)
- })
- }
- func (s *closedLocalSession) getPerspective() protocol.Perspective {
- return s.perspective
- }
- // A closedRemoteSession is a session that was closed remotely.
- // For such a session, we might receive reordered packets that were sent before the CONNECTION_CLOSE.
- // We can just ignore those packets.
- type closedRemoteSession struct {
- perspective protocol.Perspective
- }
- var _ packetHandler = &closedRemoteSession{}
- func newClosedRemoteSession(pers protocol.Perspective) packetHandler {
- return &closedRemoteSession{perspective: pers}
- }
- func (s *closedRemoteSession) handlePacket(*receivedPacket) {}
- func (s *closedRemoteSession) shutdown() {}
- func (s *closedRemoteSession) destroy(error) {}
- func (s *closedRemoteSession) getPerspective() protocol.Perspective { return s.perspective }
|