Skip to content

Commit

Permalink
Compact handshake records into less packets
Browse files Browse the repository at this point in the history
Currently each record during the handshake process is sent as a
separate packet. The dTLS spec allows for combining records into a
signal packet so long as the packet fits within the MTU. Here we
implement this improvement, compacting records during the handshake
process into less packets. The number of packets sent for a complete
handshake before this change was 12. With this change the number is
reduced to 7. While improvements are likely hard to measure, this
should reduce tail handshake latency in lossy networks.
  • Loading branch information
Ryan Gordon authored and Sean-Der committed Nov 7, 2019
1 parent 77fae27 commit 589dc6e
Show file tree
Hide file tree
Showing 5 changed files with 342 additions and 221 deletions.
153 changes: 86 additions & 67 deletions client_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,23 +289,26 @@ func clientFlightHandler(c *Conn) (bool, *alert, error) {
})
}

c.internalSend(&recordLayer{
recordLayerHeader: recordLayerHeader{
protocolVersion: protocolVersion1_2,
},
content: &handshake{
handshakeHeader: handshakeHeader{
messageSequence: uint16(c.handshakeMessageSequence),
c.bufferPacket(&packet{
record: &recordLayer{
recordLayerHeader: recordLayerHeader{
protocolVersion: protocolVersion1_2,
},
handshakeMessage: &handshakeMessageClientHello{
version: protocolVersion1_2,
cookie: c.cookie,
random: c.state.localRandom,
cipherSuites: c.localCipherSuites,
compressionMethods: defaultCompressionMethods,
extensions: extensions,
}},
}, false)
content: &handshake{
handshakeHeader: handshakeHeader{
messageSequence: uint16(c.handshakeMessageSequence),
},
handshakeMessage: &handshakeMessageClientHello{
version: protocolVersion1_2,
cookie: c.cookie,
random: c.state.localRandom,
cipherSuites: c.localCipherSuites,
compressionMethods: defaultCompressionMethods,
extensions: extensions,
}},
},
})
c.flushPacketBuffer()
case flight5:
// TODO: Better way to end handshake
if c.getRemoteEpoch() != 0 && c.getLocalEpoch() == 1 {
Expand All @@ -315,18 +318,20 @@ func clientFlightHandler(c *Conn) (bool, *alert, error) {

messageSequence := c.handshakeMessageSequence
if c.remoteRequestedCertificate {
c.internalSend(&recordLayer{
recordLayerHeader: recordLayerHeader{
protocolVersion: protocolVersion1_2,
},
content: &handshake{
handshakeHeader: handshakeHeader{
messageSequence: uint16(messageSequence),
c.bufferPacket(&packet{
record: &recordLayer{
recordLayerHeader: recordLayerHeader{
protocolVersion: protocolVersion1_2,
},
handshakeMessage: &handshakeMessageCertificate{
certificate: c.localCertificate,
}},
}, false)
content: &handshake{
handshakeHeader: handshakeHeader{
messageSequence: uint16(messageSequence),
},
handshakeMessage: &handshakeMessageCertificate{
certificate: c.localCertificate,
}},
},
})
messageSequence++
}

Expand All @@ -337,17 +342,19 @@ func clientFlightHandler(c *Conn) (bool, *alert, error) {
clientKeyExchange.identityHint = c.localPSKIdentityHint
}

c.internalSend(&recordLayer{
recordLayerHeader: recordLayerHeader{
protocolVersion: protocolVersion1_2,
},
content: &handshake{
handshakeHeader: handshakeHeader{
messageSequence: uint16(messageSequence),
c.bufferPacket(&packet{
record: &recordLayer{
recordLayerHeader: recordLayerHeader{
protocolVersion: protocolVersion1_2,
},
content: &handshake{
handshakeHeader: handshakeHeader{
messageSequence: uint16(messageSequence),
},
handshakeMessage: clientKeyExchange,
},
handshakeMessage: clientKeyExchange,
},
}, false)
})

messageSequence++

Expand Down Expand Up @@ -405,29 +412,36 @@ func clientFlightHandler(c *Conn) (bool, *alert, error) {
c.localCertificateVerify = certVerify
}

c.internalSend(&recordLayer{
recordLayerHeader: recordLayerHeader{
protocolVersion: protocolVersion1_2,
},
content: &handshake{
handshakeHeader: handshakeHeader{
messageSequence: uint16(messageSequence),
c.bufferPacket(&packet{
record: &recordLayer{
recordLayerHeader: recordLayerHeader{
protocolVersion: protocolVersion1_2,
},
handshakeMessage: &handshakeMessageCertificateVerify{
hashAlgorithm: HashAlgorithmSHA256,
signatureAlgorithm: signatureAlgorithmECDSA,
signature: c.localCertificateVerify,
}},
}, false)
content: &handshake{
handshakeHeader: handshakeHeader{
messageSequence: uint16(messageSequence),
},
handshakeMessage: &handshakeMessageCertificateVerify{
hashAlgorithm: HashAlgorithmSHA256,
signatureAlgorithm: signatureAlgorithmECDSA,
signature: c.localCertificateVerify,
}},
},
})

messageSequence++
}

c.internalSend(&recordLayer{
recordLayerHeader: recordLayerHeader{
protocolVersion: protocolVersion1_2,
c.flushPacketBuffer()

c.bufferPacket(&packet{
record: &recordLayer{
recordLayerHeader: recordLayerHeader{
protocolVersion: protocolVersion1_2,
},
content: &changeCipherSpec{},
},
content: &changeCipherSpec{},
}, false)
})

if len(c.localVerifyData) == 0 {
plainText := c.handshakeCache.pullAndMerge(
Expand All @@ -450,20 +464,25 @@ func clientFlightHandler(c *Conn) (bool, *alert, error) {
}

// TODO: Fix hard-coded epoch, taking retransmitting into account.
atomic.StoreUint64(&c.state.localSequenceNumber, 0)
c.internalSend(&recordLayer{
recordLayerHeader: recordLayerHeader{
epoch: 1,
protocolVersion: protocolVersion1_2,
},
content: &handshake{
handshakeHeader: handshakeHeader{
messageSequence: uint16(messageSequence),
c.bufferPacket(&packet{
record: &recordLayer{
recordLayerHeader: recordLayerHeader{
epoch: 1,
protocolVersion: protocolVersion1_2,
},
handshakeMessage: &handshakeMessageFinished{
verifyData: c.localVerifyData,
}},
}, true)
content: &handshake{
handshakeHeader: handshakeHeader{
messageSequence: uint16(messageSequence),
},
handshakeMessage: &handshakeMessageFinished{
verifyData: c.localVerifyData,
}},
},
shouldEncrypt: true,
resetLocalSequenceNumber: true,
})

c.flushPacketBuffer()
default:
return false, &alert{alertLevelFatal, alertUnexpectedMessage}, fmt.Errorf("unhandled flight %s", c.currFlight.get())
}
Expand Down
Loading

0 comments on commit 589dc6e

Please sign in to comment.