-
Notifications
You must be signed in to change notification settings - Fork 0
/
protocol_quic_frame.py
103 lines (89 loc) · 3.08 KB
/
protocol_quic_frame.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
from metatype import OpaqueLength, Uint8, Uint32, VarLenIntEncoding, Type, Enum
import metastruct as meta
from utils import hexdump
from protocol_handshake import Handshake
class FrameType(Enum):
elem_t = VarLenIntEncoding
PADDING = VarLenIntEncoding(Uint8(0x00))
ACK = VarLenIntEncoding(Uint8(0x02))
CRYPTO = VarLenIntEncoding(Uint8(0x06))
# PADDING Frame {
# Type (i) = 0x00,
# }
class Padding(Type):
def __init__(self, padding: bytes):
self.padding = padding
@classmethod
def from_stream(cls, fs, parent=None):
padding = bytearray()
while True:
data = fs.read(1)
if len(data) <= 0:
break
if data == b'\x00':
padding.append(ord(data))
else:
fs.seek(-1, 1) # seek -1 from current position (1)
return Padding(padding)
def __bytes__(self):
return bytes(self.padding)
def __repr__(self):
return 'Padding[%d]' % (len(self.padding) + 1)
# ACK Frame {
# Type (i) = 0x02..0x03,
# Largest Acknowledged (i),
# ACK Delay (i),
# ACK Range Count (i),
# First ACK Range (i),
# ACK Range (..) ...,
# [ECN Counts (..)], <= only exists when type is 0x03
# }
@meta.struct
class AckRange(meta.MetaStruct):
gap: VarLenIntEncoding
ack_range_length: VarLenIntEncoding
# ECN (Explicit Congestion Notification)
# 輻輳が発生したことを通知するときに用いられる。
@meta.struct
class AckFrame(meta.MetaStruct):
largest_acknowledged: VarLenIntEncoding
ack_delay: VarLenIntEncoding
ack_range_count: VarLenIntEncoding # ここは0しか入らないとして、今はACK Rangesのことは考えない
first_ack_range: VarLenIntEncoding
# ack_range: AckRange
# CRYPTO Frame {
# Type (i) = 0x06,
# Offset (i),
# Length (i),
# Crypto Data (..),
# }
# 最初のデータで、dataがHandshakeとして復元できない場合は未完全の可能性があるので、後続のCRYPTO Frameを待つ。
# Offset≠0のときは、Handshakeデータが分割されている部分に埋め込んで復元する。
# 送信時で分割する必要がない場合は以下のCryptoFrameクラスを使う。
@meta.struct
class CryptoFrame(meta.MetaStruct):
offset: VarLenIntEncoding
length: VarLenIntEncoding = lambda self: VarLenIntEncoding(Uint32(len(bytes(self.data))))
data: Handshake
# 受信時で分割されている可能性がある場合は以下のCryptoFrameSplitを使う。
@meta.struct
class CryptoFrameSplit(meta.MetaStruct):
offset: VarLenIntEncoding
length: VarLenIntEncoding
data: OpaqueLength
# 分割されていない場合
@meta.struct
class Frame(meta.MetaStruct):
frame_type: FrameType
frame_content: meta.Select('frame_type', cases={
FrameType.PADDING: Padding,
FrameType.ACK: AckFrame,
FrameType.CRYPTO: CryptoFrame,
})
# 分割されている場合
@meta.struct
class FrameSplit(meta.MetaStruct):
frame_type: FrameType
frame_content: meta.Select('frame_type', cases={
FrameType.CRYPTO: CryptoFrameSplit,
})