Skip to content

Commit 160fcda

Browse files
committed
Add optimizations for connection & handshake
1 parent 848c4bc commit 160fcda

5 files changed

Lines changed: 69 additions & 18 deletions

File tree

conn.go

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,12 @@ func (c *Conn) compactRawPackets(rawPackets [][]byte) [][]byte {
595595
currentCombinedRawPacket := make([]byte, 0)
596596

597597
for _, rawPacket := range rawPackets {
598-
if len(currentCombinedRawPacket) > 0 && len(currentCombinedRawPacket)+len(rawPacket) >= c.maximumTransmissionUnit {
598+
if len(currentCombinedRawPacket) == 0 && len(rawPacket) >= c.maximumTransmissionUnit {
599+
combinedRawPackets = append(combinedRawPackets, rawPacket)
600+
601+
continue
602+
} else if len(currentCombinedRawPacket) > 0 &&
603+
len(currentCombinedRawPacket)+len(rawPacket) >= c.maximumTransmissionUnit {
599604
combinedRawPackets = append(combinedRawPackets, currentCombinedRawPacket)
600605
currentCombinedRawPacket = []byte{}
601606
}
@@ -674,7 +679,7 @@ func (c *Conn) processPacket(pkt *packet) ([]byte, error) { //nolint:cyclop
674679

675680
//nolint:cyclop
676681
func (c *Conn) processHandshakePacket(pkt *packet, dtlsHandshake *handshake.Handshake) ([][]byte, error) {
677-
rawPackets := make([][]byte, 0)
682+
var rawPackets [][]byte
678683

679684
handshakeFragments, err := c.fragmentHandshake(dtlsHandshake)
680685
if err != nil {
@@ -710,12 +715,15 @@ func (c *Conn) processHandshakePacket(pkt *packet, dtlsHandshake *handshake.Hand
710715
ConnectionID: c.state.remoteConnectionID,
711716
SequenceNumber: pkt.record.Header.SequenceNumber,
712717
}
713-
rawPacket, err = cidHeader.Marshal()
718+
719+
hs := recordlayer.FixedHeaderSize + len(cidHeader.ConnectionID)
720+
rawPacket = make([]byte, hs+len(rawInner))
721+
err = cidHeader.MarshalInto(rawPacket)
714722
if err != nil {
715723
return nil, err
716724
}
717725
pkt.record.Header = *cidHeader
718-
rawPacket = append(rawPacket, rawInner...)
726+
copy(rawPacket[hs:], rawInner)
719727
} else {
720728
recordlayerHeader := &recordlayer.Header{
721729
Version: pkt.record.Header.Version,
@@ -725,13 +733,15 @@ func (c *Conn) processHandshakePacket(pkt *packet, dtlsHandshake *handshake.Hand
725733
SequenceNumber: seq,
726734
}
727735

728-
rawPacket, err = recordlayerHeader.Marshal()
736+
hs := recordlayer.FixedHeaderSize + len(recordlayerHeader.ConnectionID)
737+
rawPacket = make([]byte, hs+len(handshakeFragment))
738+
err = recordlayerHeader.MarshalInto(rawPacket)
729739
if err != nil {
730740
return nil, err
731741
}
732742

733743
pkt.record.Header = *recordlayerHeader
734-
rawPacket = append(rawPacket, handshakeFragment...)
744+
copy(rawPacket[hs:], handshakeFragment)
735745
}
736746

737747
if pkt.shouldEncrypt {
@@ -754,14 +764,9 @@ func (c *Conn) fragmentHandshake(dtlsHandshake *handshake.Handshake) ([][]byte,
754764
return nil, err
755765
}
756766

757-
fragmentedHandshakes := make([][]byte, 0)
767+
var fragmentedHandshakes [][]byte
758768

759769
contentFragments := splitBytes(content, c.maximumTransmissionUnit)
760-
if len(contentFragments) == 0 {
761-
contentFragments = [][]byte{
762-
{},
763-
}
764-
}
765770

766771
offset := 0
767772
for _, contentFragment := range contentFragments {
@@ -777,12 +782,13 @@ func (c *Conn) fragmentHandshake(dtlsHandshake *handshake.Handshake) ([][]byte,
777782

778783
offset += contentFragmentLen
779784

780-
fragmentedHandshake, err := headerFragment.Marshal()
785+
fragmentedHandshake := make([]byte, handshake.HeaderLength+len(contentFragment))
786+
err := headerFragment.MarshalInto(fragmentedHandshake)
781787
if err != nil {
782788
return nil, err
783789
}
784790

785-
fragmentedHandshake = append(fragmentedHandshake, contentFragment...)
791+
copy(fragmentedHandshake[handshake.HeaderLength:], contentFragment)
786792
fragmentedHandshakes = append(fragmentedHandshakes, fragmentedHandshake)
787793
}
788794

errors.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ var (
143143
//nolint:err113
144144
errFailedToAccessPoolReadBuffer = &InternalError{Err: errors.New("failed to access pool read buffer")}
145145
//nolint:err113
146+
errFailedToAccessPoolTimer = &InternalError{Err: errors.New("failed to access pool timer")}
147+
//nolint:err113
146148
errFragmentBufferOverflow = &InternalError{Err: errors.New("fragment buffer overflow")}
147149

148150
//nolint:err113

handshaker.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,15 @@ func (s *handshakeFSM) send(ctx context.Context, c flightConn) (handshakeState,
275275
return handshakeWaiting, nil
276276
}
277277

278+
var timerPool = sync.Pool{ //nolint:gochecknoglobals
279+
New: func() any {
280+
t := time.NewTimer(time.Millisecond)
281+
t.Stop()
282+
283+
return t
284+
},
285+
}
286+
278287
func (s *handshakeFSM) wait(ctx context.Context, conn flightConn) (handshakeState, error) { //nolint:gocognit,cyclop
279288
parse, errFlight := s.currentFlight.getFlightParser()
280289
if errFlight != nil {
@@ -285,7 +294,15 @@ func (s *handshakeFSM) wait(ctx context.Context, conn flightConn) (handshakeStat
285294
return handshakeErrored, errFlight
286295
}
287296

288-
retransmitTimer := time.NewTimer(s.retransmitInterval)
297+
retransmitTimer, ok := timerPool.Get().(*time.Timer)
298+
if !ok {
299+
return handshakeErrored, errFailedToAccessPoolTimer
300+
}
301+
defer func() {
302+
retransmitTimer.Stop()
303+
timerPool.Put(retransmitTimer)
304+
}()
305+
retransmitTimer.Reset(s.retransmitInterval)
289306
for {
290307
select {
291308
case state := <-conn.recvHandshake():

pkg/protocol/handshake/header.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,24 @@ type Header struct {
2929
// Marshal encodes the Header.
3030
func (h *Header) Marshal() ([]byte, error) {
3131
out := make([]byte, HeaderLength)
32+
err := h.MarshalInto(out)
33+
34+
return out, err
35+
}
36+
37+
// MarshalInto encodes the Header using a pre-allocated buffer.
38+
func (h *Header) MarshalInto(out []byte) error {
39+
if len(out) < HeaderLength {
40+
return errBufferTooSmall
41+
}
3242

3343
out[0] = byte(h.Type)
3444
util.PutBigEndianUint24(out[1:], h.Length)
3545
binary.BigEndian.PutUint16(out[4:], h.MessageSequence)
3646
util.PutBigEndianUint24(out[6:], h.FragmentOffset)
3747
util.PutBigEndianUint24(out[9:], h.FragmentLength)
3848

39-
return out, nil
49+
return nil
4050
}
4151

4252
// Unmarshal populates the header from encoded data.

pkg/protocol/recordlayer/header.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,24 @@ func (h *Header) Marshal() ([]byte, error) {
3737
}
3838

3939
hs := FixedHeaderSize + len(h.ConnectionID)
40-
4140
out := make([]byte, hs)
41+
err := h.MarshalInto(out)
42+
43+
return out, err
44+
}
45+
46+
// MarshalInto encodes a TLS RecordLayer Header to binary using pre-allocated buffer.
47+
func (h *Header) MarshalInto(out []byte) error {
48+
if h.SequenceNumber > MaxSequenceNumber {
49+
return errSequenceNumberOverflow
50+
}
51+
52+
hs := FixedHeaderSize + len(h.ConnectionID)
53+
54+
if len(out) < hs {
55+
return errBufferTooSmall
56+
}
57+
4258
out[0] = byte(h.ContentType)
4359
out[1] = h.Version.Major
4460
out[2] = h.Version.Minor
@@ -47,7 +63,7 @@ func (h *Header) Marshal() ([]byte, error) {
4763
copy(out[11:11+len(h.ConnectionID)], h.ConnectionID)
4864
binary.BigEndian.PutUint16(out[hs-2:], h.ContentLen)
4965

50-
return out, nil
66+
return nil
5167
}
5268

5369
// Unmarshal populates a TLS RecordLayer Header from binary.

0 commit comments

Comments
 (0)