detached 2479821

test(dgram): synchronize malformed fragment rejection

commit
2479821c091ae9e0930baff9f47315a25b858c22
author
brice · · 2026-07-10 00:23 UTC
parent
b9e591f
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +42 -29
M internal/adapters/dgram/network_sim_test.go +5 -1
@@ -502,11 +502,15 @@ func TestMalformedAuthenticatedFragmentDoesNotCountAsContact(t *testing.T) {
502502 if err != nil {
503503 t.Fatal(err)
504504 }
505+ malformedRejected := make(chan struct{}, 1)
506+ b.mu.Lock()
507+ b.afterMalformedFragment = func() { malformedRejected <- struct{}{} }
508+ b.mu.Unlock()
505509 clk.advance(time.Second)
506510 if _, err := aPC.WriteTo(codec.Seal(1, 999, []byte("not a fragment"), nil), bPC.addr); err != nil {
507511 t.Fatal(err)
508512 }
509- awaitSignal(t, bPC.read, "malformed datagram read")
513+ awaitSignal(t, malformedRejected, "malformed fragment rejection")
510514 b.mu.Lock()
511515 gotPacket, gotRecord := b.lastAuthenticatedPacket, b.lastCompleteRecord
512516 b.mu.Unlock()
@@ -502,11 +502,15 @@ func TestMalformedAuthenticatedFragmentDoesNotCountAsContact(t *testing.T) {
502 if err != nil {502 if err != nil {
503 t.Fatal(err)503 t.Fatal(err)
504 }504 }
505+ malformedRejected := make(chan struct{}, 1)
506+ b.mu.Lock()
507+ b.afterMalformedFragment = func() { malformedRejected <- struct{}{} }
508+ b.mu.Unlock()
505 clk.advance(time.Second)509 clk.advance(time.Second)
506 if _, err := aPC.WriteTo(codec.Seal(1, 999, []byte("not a fragment"), nil), bPC.addr); err != nil {510 if _, err := aPC.WriteTo(codec.Seal(1, 999, []byte("not a fragment"), nil), bPC.addr); err != nil {
507 t.Fatal(err)511 t.Fatal(err)
508 }512 }
509- awaitSignal(t, bPC.read, "malformed datagram read")513+ awaitSignal(t, malformedRejected, "malformed fragment rejection")
510 b.mu.Lock()514 b.mu.Lock()
511 gotPacket, gotRecord := b.lastAuthenticatedPacket, b.lastCompleteRecord515 gotPacket, gotRecord := b.lastAuthenticatedPacket, b.lastCompleteRecord
512 b.mu.Unlock()516 b.mu.Unlock()
M internal/adapters/dgram/transport.go +37 -28
@@ -156,34 +156,37 @@ type Transport struct {
156156 // afterAuthenticatedPacket is a test synchronization hook. It runs after
157157 // authenticated-contact state has been committed.
158158 afterAuthenticatedPacket func()
159- observe DiagnosticObserver
160- diagnosticCh chan Diagnostic
161- heartbeat time.Duration
162- resendAfter time.Duration
163- maxResendAfter time.Duration
164- maxResendPerTick int
165- srtt time.Duration
166- rttvar time.Duration
167- rto time.Duration
168- writeTimeout time.Duration
169- degradedAfter time.Duration
170- probeAfter time.Duration
171- offlineAfter time.Duration
172- deadAfter time.Duration
173- maxPending int
174- maxPendingWait time.Duration
175- maxRecvBuffer int
176- clock ports.Clock
177- linkState ports.LinkState
178- linkEvents chan ports.LinkEvent
179- probeWait map[uint64]chan struct{}
180- sendWake chan struct{}
181- probeReply chan uint64
182- rebind func(net.PacketConn) (net.PacketConn, error)
183- hoppedOffline bool
184- outputQueue []queuedSend
185- outputWake chan struct{}
186- outputNext time.Time
159+ // afterMalformedFragment is a test synchronization hook. It runs after an
160+ // authenticated datagram has been rejected as an invalid fragment.
161+ afterMalformedFragment func()
162+ observe DiagnosticObserver
163+ diagnosticCh chan Diagnostic
164+ heartbeat time.Duration
165+ resendAfter time.Duration
166+ maxResendAfter time.Duration
167+ maxResendPerTick int
168+ srtt time.Duration
169+ rttvar time.Duration
170+ rto time.Duration
171+ writeTimeout time.Duration
172+ degradedAfter time.Duration
173+ probeAfter time.Duration
174+ offlineAfter time.Duration
175+ deadAfter time.Duration
176+ maxPending int
177+ maxPendingWait time.Duration
178+ maxRecvBuffer int
179+ clock ports.Clock
180+ linkState ports.LinkState
181+ linkEvents chan ports.LinkEvent
182+ probeWait map[uint64]chan struct{}
183+ sendWake chan struct{}
184+ probeReply chan uint64
185+ rebind func(net.PacketConn) (net.PacketConn, error)
186+ hoppedOffline bool
187+ outputQueue []queuedSend
188+ outputWake chan struct{}
189+ outputNext time.Time
187190
188191 recvMu sync.Mutex
189192 replay *pdgram.ReplayWindow
@@ -693,6 +696,12 @@ func (t *Transport) readLoop(pc net.PacketConn) {
693696 frag, err := pdgram.UnmarshalFragment(pt)
694697 if err != nil {
695698 t.recvMu.Unlock()
699+ t.mu.Lock()
700+ afterMalformed := t.afterMalformedFragment
701+ t.mu.Unlock()
702+ if afterMalformed != nil {
703+ afterMalformed()
704+ }
696705 continue
697706 }
698707 payload, complete, err := t.reasm.Add(frag)
@@ -156,34 +156,37 @@ type Transport struct {
156 // afterAuthenticatedPacket is a test synchronization hook. It runs after156 // afterAuthenticatedPacket is a test synchronization hook. It runs after
157 // authenticated-contact state has been committed.157 // authenticated-contact state has been committed.
158 afterAuthenticatedPacket func()158 afterAuthenticatedPacket func()
159- observe DiagnosticObserver159+ // afterMalformedFragment is a test synchronization hook. It runs after an
160- diagnosticCh chan Diagnostic160+ // authenticated datagram has been rejected as an invalid fragment.
161- heartbeat time.Duration161+ afterMalformedFragment func()
162- resendAfter time.Duration162+ observe DiagnosticObserver
163- maxResendAfter time.Duration163+ diagnosticCh chan Diagnostic
164- maxResendPerTick int164+ heartbeat time.Duration
165- srtt time.Duration165+ resendAfter time.Duration
166- rttvar time.Duration166+ maxResendAfter time.Duration
167- rto time.Duration167+ maxResendPerTick int
168- writeTimeout time.Duration168+ srtt time.Duration
169- degradedAfter time.Duration169+ rttvar time.Duration
170- probeAfter time.Duration170+ rto time.Duration
171- offlineAfter time.Duration171+ writeTimeout time.Duration
172- deadAfter time.Duration172+ degradedAfter time.Duration
173- maxPending int173+ probeAfter time.Duration
174- maxPendingWait time.Duration174+ offlineAfter time.Duration
175- maxRecvBuffer int175+ deadAfter time.Duration
176- clock ports.Clock176+ maxPending int
177- linkState ports.LinkState177+ maxPendingWait time.Duration
178- linkEvents chan ports.LinkEvent178+ maxRecvBuffer int
179- probeWait map[uint64]chan struct{}179+ clock ports.Clock
180- sendWake chan struct{}180+ linkState ports.LinkState
181- probeReply chan uint64181+ linkEvents chan ports.LinkEvent
182- rebind func(net.PacketConn) (net.PacketConn, error)182+ probeWait map[uint64]chan struct{}
183- hoppedOffline bool183+ sendWake chan struct{}
184- outputQueue []queuedSend184+ probeReply chan uint64
185- outputWake chan struct{}185+ rebind func(net.PacketConn) (net.PacketConn, error)
186- outputNext time.Time186+ hoppedOffline bool
187+ outputQueue []queuedSend
188+ outputWake chan struct{}
189+ outputNext time.Time
187 190
188 recvMu sync.Mutex191 recvMu sync.Mutex
189 replay *pdgram.ReplayWindow192 replay *pdgram.ReplayWindow
@@ -693,6 +696,12 @@ func (t *Transport) readLoop(pc net.PacketConn) {
693 frag, err := pdgram.UnmarshalFragment(pt)696 frag, err := pdgram.UnmarshalFragment(pt)
694 if err != nil {697 if err != nil {
695 t.recvMu.Unlock()698 t.recvMu.Unlock()
699+ t.mu.Lock()
700+ afterMalformed := t.afterMalformedFragment
701+ t.mu.Unlock()
702+ if afterMalformed != nil {
703+ afterMalformed()
704+ }
696 continue705 continue
697 }706 }
698 payload, complete, err := t.reasm.Add(frag)707 payload, complete, err := t.reasm.Add(frag)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close