@@ -67,6 +67,8 @@ const (
67
67
// The maximum write buffer size. This *must* be multiple of
68
68
// altsRecordDefaultLength.
69
69
altsWriteBufferMaxSize = 512 * 1024 // 512KiB
70
+ // The initial buffer used to read from the network.
71
+ altsReadBufferInitialSize = 32 * 1024 // 32KiB
70
72
)
71
73
72
74
var (
@@ -87,7 +89,7 @@ type conn struct {
87
89
net.Conn
88
90
crypto ALTSRecordCrypto
89
91
// buf holds data that has been read from the connection and decrypted,
90
- // but has not yet been returned by Read.
92
+ // but has not yet been returned by Read. It is a sub-slice of protected.
91
93
buf []byte
92
94
payloadLengthLimit int
93
95
// protected holds data read from the network but have not yet been
@@ -115,21 +117,13 @@ func NewConn(c net.Conn, side core.Side, recordProtocol string, key []byte, prot
115
117
}
116
118
overhead := MsgLenFieldSize + msgTypeFieldSize + crypto .EncryptionOverhead ()
117
119
payloadLengthLimit := altsRecordDefaultLength - overhead
118
- var protectedBuf []byte
119
- if protected == nil {
120
- // We pre-allocate protected to be of size
121
- // 2*altsRecordDefaultLength-1 during initialization. We only
122
- // read from the network into protected when protected does not
123
- // contain a complete frame, which is at most
124
- // altsRecordDefaultLength-1 (bytes). And we read at most
125
- // altsRecordDefaultLength (bytes) data into protected at one
126
- // time. Therefore, 2*altsRecordDefaultLength-1 is large enough
127
- // to buffer data read from the network.
128
- protectedBuf = make ([]byte , 0 , 2 * altsRecordDefaultLength - 1 )
129
- } else {
130
- protectedBuf = make ([]byte , len (protected ))
131
- copy (protectedBuf , protected )
132
- }
120
+ // We pre-allocate protected to be of size 32KB during initialization.
121
+ // We increase the size of the buffer by the required amount if it can't
122
+ // hold a complete encrypted record.
123
+ protectedBuf := make ([]byte , max (altsReadBufferInitialSize , len (protected )))
124
+ // Copy additional data from hanshaker service.
125
+ copy (protectedBuf , protected )
126
+ protectedBuf = protectedBuf [:len (protected )]
133
127
134
128
altsConn := & conn {
135
129
Conn : c ,
@@ -166,11 +160,26 @@ func (p *conn) Read(b []byte) (n int, err error) {
166
160
// Check whether a complete frame has been received yet.
167
161
for len (framedMsg ) == 0 {
168
162
if len (p .protected ) == cap (p .protected ) {
169
- tmp := make ([]byte , len (p .protected ), cap (p .protected )+ altsRecordDefaultLength )
170
- copy (tmp , p .protected )
171
- p .protected = tmp
163
+ // We can parse the length header to know exactly how large
164
+ // the buffer needs to be to hold the entire frame.
165
+ length , didParse := parseMessageLength (p .protected )
166
+ if ! didParse {
167
+ // The protected buffer is initialized with a capacity of
168
+ // larger than 4B. It should always hold the message length
169
+ // header.
170
+ panic (fmt .Sprintf ("protected buffer length shorter than expected: %d vs %d" , len (p .protected ), MsgLenFieldSize ))
171
+ }
172
+ oldProtectedBuf := p .protected
173
+ // The new buffer must be able to hold the message length header
174
+ // and the entire message.
175
+ requiredCapacity := int (length ) + MsgLenFieldSize
176
+ p .protected = make ([]byte , requiredCapacity )
177
+ // Copy the contents of the old buffer and set the length of the
178
+ // new buffer to the number of bytes already read.
179
+ copy (p .protected , oldProtectedBuf )
180
+ p .protected = p .protected [:len (oldProtectedBuf )]
172
181
}
173
- n , err = p .Conn .Read (p .protected [len (p .protected ):min ( cap (p .protected ), len ( p . protected ) + altsRecordDefaultLength )])
182
+ n , err = p .Conn .Read (p .protected [len (p .protected ):cap (p .protected )])
174
183
if err != nil {
175
184
return 0 , err
176
185
}
@@ -189,6 +198,15 @@ func (p *conn) Read(b []byte) (n int, err error) {
189
198
}
190
199
ciphertext := msg [msgTypeFieldSize :]
191
200
201
+ // Decrypt directly into the buffer, avoiding a copy from p.buf if
202
+ // possible.
203
+ if len (b ) >= len (ciphertext ) {
204
+ dec , err := p .crypto .Decrypt (b [:0 ], ciphertext )
205
+ if err != nil {
206
+ return 0 , err
207
+ }
208
+ return len (dec ), nil
209
+ }
192
210
// Decrypt requires that if the dst and ciphertext alias, they
193
211
// must alias exactly. Code here used to use msg[:0], but msg
194
212
// starts MsgLenFieldSize+msgTypeFieldSize bytes earlier than
0 commit comments