Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

device: reduce RoutineHandshake allocations #116

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions device/noise-protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package device

import (
"encoding/binary"
"errors"
"fmt"
"sync"
Expand Down Expand Up @@ -115,6 +116,53 @@ type MessageCookieReply struct {
Cookie [blake2s.Size128 + poly1305.TagSize]byte
}

var errMessageTooShort = errors.New("message too short")

func (msg *MessageInitiation) unmarshal(b []byte) error {
if len(b) < MessageInitiationSize {
return errMessageTooShort
}
Comment on lines +121 to +124
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe name it reset.

Also the size of the packet is checked earlier

case MessageInitiationType:
if len(packet) != MessageInitiationSize {
continue
}
case MessageResponseType:
if len(packet) != MessageResponseSize {
continue
}
case MessageCookieReplyType:
if len(packet) != MessageCookieReplySize {
continue
}

so this check could be removed as well as error result check at the callsite.


msg.Type = binary.LittleEndian.Uint32(b)
msg.Sender = binary.LittleEndian.Uint32(b[4:])
copy(msg.Ephemeral[:], b[8:])
copy(msg.Static[:], b[8+len(msg.Ephemeral):])
copy(msg.Timestamp[:], b[8+len(msg.Ephemeral)+len(msg.Static):])
copy(msg.MAC1[:], b[8+len(msg.Ephemeral)+len(msg.Static)+len(msg.Timestamp):])
copy(msg.MAC2[:], b[8+len(msg.Ephemeral)+len(msg.Static)+len(msg.Timestamp)+len(msg.MAC1):])

return nil
}

func (msg *MessageResponse) unmarshal(b []byte) error {
if len(b) < MessageResponseSize {
return errMessageTooShort
}

msg.Type = binary.LittleEndian.Uint32(b)
msg.Sender = binary.LittleEndian.Uint32(b[4:])
msg.Receiver = binary.LittleEndian.Uint32(b[8:])
copy(msg.Ephemeral[:], b[12:])
copy(msg.Empty[:], b[12+len(msg.Ephemeral):])
copy(msg.MAC1[:], b[12+len(msg.Ephemeral)+len(msg.Empty):])
copy(msg.MAC2[:], b[12+len(msg.Ephemeral)+len(msg.Empty)+len(msg.MAC1):])

return nil
}

func (msg *MessageCookieReply) unmarshal(b []byte) error {
if len(b) < MessageCookieReplySize {
return errMessageTooShort
}

msg.Type = binary.LittleEndian.Uint32(b)
msg.Receiver = binary.LittleEndian.Uint32(b[4:])
copy(msg.Nonce[:], b[8:])
copy(msg.Cookie[:], b[8+len(msg.Nonce):])

return nil
}

type Handshake struct {
state handshakeState
mutex sync.RWMutex
Expand Down
26 changes: 12 additions & 14 deletions device/receive.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
package device

import (
"bytes"
"encoding/binary"
"errors"
"net"
Expand Down Expand Up @@ -276,6 +275,11 @@ func (device *Device) RoutineHandshake(id int) {
}()
device.log.Verbosef("Routine: handshake worker %d - started", id)

var (
msgCookieReply MessageCookieReply
msgInitiation MessageInitiation
msgResponse MessageResponse
)
for elem := range device.queue.handshake.c {

// handle cookie fields and ratelimiting
Expand All @@ -286,17 +290,15 @@ func (device *Device) RoutineHandshake(id int) {

// unmarshal packet

var reply MessageCookieReply
reader := bytes.NewReader(elem.packet)
Copy link
Author

@AlexanderYastrebov AlexanderYastrebov Jan 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here byte reader can be replaced with https://pkg.go.dev/encoding/binary#Decode added in 1.23 golang/go#60023 (comment)

err := binary.Read(reader, binary.LittleEndian, &reply)
err := msgCookieReply.unmarshal(elem.packet)
if err != nil {
device.log.Verbosef("Failed to decode cookie reply")
goto skip
}

// lookup peer from index

entry := device.indexTable.Lookup(reply.Receiver)
entry := device.indexTable.Lookup(msgCookieReply.Receiver)

if entry.peer == nil {
goto skip
Expand All @@ -306,7 +308,7 @@ func (device *Device) RoutineHandshake(id int) {

if peer := entry.peer; peer.isRunning.Load() {
device.log.Verbosef("Receiving cookie response from %s", elem.endpoint.DstToString())
if !peer.cookieGenerator.ConsumeReply(&reply) {
if !peer.cookieGenerator.ConsumeReply(&msgCookieReply) {
device.log.Verbosef("Could not decrypt invalid cookie response")
}
}
Expand Down Expand Up @@ -352,17 +354,15 @@ func (device *Device) RoutineHandshake(id int) {

// unmarshal

var msg MessageInitiation
reader := bytes.NewReader(elem.packet)
err := binary.Read(reader, binary.LittleEndian, &msg)
err := msgInitiation.unmarshal(elem.packet)
if err != nil {
device.log.Errorf("Failed to decode initiation message")
goto skip
}

// consume initiation

peer := device.ConsumeMessageInitiation(&msg)
peer := device.ConsumeMessageInitiation(&msgInitiation)
if peer == nil {
device.log.Verbosef("Received invalid initiation message from %s", elem.endpoint.DstToString())
goto skip
Expand All @@ -385,17 +385,15 @@ func (device *Device) RoutineHandshake(id int) {

// unmarshal

var msg MessageResponse
reader := bytes.NewReader(elem.packet)
err := binary.Read(reader, binary.LittleEndian, &msg)
err := msgResponse.unmarshal(elem.packet)
if err != nil {
device.log.Errorf("Failed to decode response message")
goto skip
}

// consume response

peer := device.ConsumeMessageResponse(&msg)
peer := device.ConsumeMessageResponse(&msgResponse)
if peer == nil {
device.log.Verbosef("Received invalid response message from %s", elem.endpoint.DstToString())
goto skip
Expand Down