1package quic
2
3import (
4	"fmt"
5
6	"github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/quic-go/internal/protocol"
7	"github.com/ooni/psiphon/oopsi/github.com/Psiphon-Labs/quic-go/internal/wire"
8)
9
10type cryptoDataHandler interface {
11	HandleMessage([]byte, protocol.EncryptionLevel) bool
12}
13
14type cryptoStreamManager struct {
15	cryptoHandler cryptoDataHandler
16
17	initialStream   cryptoStream
18	handshakeStream cryptoStream
19	oneRTTStream    cryptoStream
20}
21
22func newCryptoStreamManager(
23	cryptoHandler cryptoDataHandler,
24	initialStream cryptoStream,
25	handshakeStream cryptoStream,
26	oneRTTStream cryptoStream,
27) *cryptoStreamManager {
28	return &cryptoStreamManager{
29		cryptoHandler:   cryptoHandler,
30		initialStream:   initialStream,
31		handshakeStream: handshakeStream,
32		oneRTTStream:    oneRTTStream,
33	}
34}
35
36func (m *cryptoStreamManager) HandleCryptoFrame(frame *wire.CryptoFrame, encLevel protocol.EncryptionLevel) (bool /* encryption level changed */, error) {
37	var str cryptoStream
38	switch encLevel {
39	case protocol.EncryptionInitial:
40		str = m.initialStream
41	case protocol.EncryptionHandshake:
42		str = m.handshakeStream
43	case protocol.Encryption1RTT:
44		str = m.oneRTTStream
45	default:
46		return false, fmt.Errorf("received CRYPTO frame with unexpected encryption level: %s", encLevel)
47	}
48	if err := str.HandleCryptoFrame(frame); err != nil {
49		return false, err
50	}
51	for {
52		data := str.GetCryptoData()
53		if data == nil {
54			return false, nil
55		}
56		if encLevelFinished := m.cryptoHandler.HandleMessage(data, encLevel); encLevelFinished {
57			return true, str.Finish()
58		}
59	}
60}
61