Skip to content

Commit 4fce47f

Browse files
feat(backend): add handler to detect disonnecction
1 parent 9b9ba5b commit 4fce47f

6 files changed

Lines changed: 49 additions & 2 deletions

File tree

backend/cmd/config.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ validate = true # Execute ADJ validator before starting backend
2020
# Transport Configuration
2121
[transport]
2222
propagate_fault = true
23+
max_packet_interval_us = 100000 # Max interval (us) between two UDP packets of the same id before propagating a fault (0 disables the check)
2324

2425
# TCP Configuration
2526
# These settings control how the backend reconnects to boards when connections are lost

backend/cmd/dev-config.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ validate = true # Execute ADJ validator before starting backend
2222
# Transport Configuration
2323
[transport]
2424
propagate_fault = false
25+
max_packet_interval_us = 100 # Max interval (us) between two UDP packets of the same id before propagating a fault (0 disables the check)
2526

2627
# TCP Configuration
2728
# These settings control how the backend reconnects to boards when connections are lost

backend/cmd/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
_ "net/http/pprof"
55
"os"
66
"os/signal"
7+
"time"
78

89
"github.com/HyperloopUPV-H8/h9-backend/internal/config"
910
"github.com/HyperloopUPV-H8/h9-backend/internal/flags"
@@ -97,6 +98,7 @@ func main() {
9798
// <--- transport --->
9899
transp := transport.NewTransport(trace.Logger)
99100
transp.SetpropagateFault(config.Transport.PropagateFault)
101+
transp.SetMaxPacketInterval(time.Duration(config.Transport.MaxPacketIntervalUs) * time.Microsecond)
100102

101103
// <--- vehicle --->
102104
err = configureVehicle(

backend/internal/config/config_types.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ type Adj struct {
1212
}
1313

1414
type Transport struct {
15-
PropagateFault bool `toml:"propagate_fault"`
15+
PropagateFault bool `toml:"propagate_fault"`
16+
MaxPacketIntervalUs int64 `toml:"max_packet_interval_us"`
1617
}
1718

1819
type TCP struct {

backend/pkg/transport/constructor.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package transport
33
import (
44
"net"
55
"sync"
6+
"time"
67

78
"github.com/HyperloopUPV-H8/h9-backend/pkg/abstraction"
89
"github.com/HyperloopUPV-H8/h9-backend/pkg/transport/presentation"
@@ -16,6 +17,8 @@ func NewTransport(baseLogger zerolog.Logger) *Transport {
1617
idToTarget: make(map[abstraction.PacketId]abstraction.TransportTarget),
1718
ipToTarget: make(map[string]abstraction.TransportTarget),
1819

20+
lastPacketTime: make(map[abstraction.PacketId]time.Time),
21+
1922
logger: baseLogger,
2023
errChan: make(chan error, 100),
2124
}

backend/pkg/transport/transport.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ type Transport struct {
3434
ipToTarget map[string]abstraction.TransportTarget
3535
idToTarget map[abstraction.PacketId]abstraction.TransportTarget
3636

37-
propagateFault bool
37+
propagateFault bool
38+
maxPacketInterval time.Duration
39+
lastPacketTime map[abstraction.PacketId]time.Time
3840

3941
api abstraction.TransportAPI
4042

@@ -413,6 +415,8 @@ func (transport *Transport) handleUDPPacket(udpPacket udp.Packet) {
413415
transport.replicateFault(packet, transport.logger)
414416
}
415417

418+
transport.checkPacketInterval(packet.Id(), udpPacket.Timestamp)
419+
416420
// Send notification
417421
transport.api.Notification(NewPacketNotification(packet, srcAddr, dstAddr, udpPacket.Timestamp))
418422

@@ -421,6 +425,34 @@ func (transport *Transport) handleUDPPacket(udpPacket udp.Packet) {
421425
}
422426
}
423427

428+
// checkPacketInterval propagates a fault when the time between two consecutive
429+
// UDP packets with the same id exceeds maxPacketInterval. Fault packets (id 0)
430+
// are excluded. lastPacketTime needs no locking because this is only called
431+
// from the HandleUDPServer goroutine.
432+
func (transport *Transport) checkPacketInterval(id abstraction.PacketId, timestamp time.Time) {
433+
if !transport.propagateFault || transport.maxPacketInterval <= 0 || id == 0 {
434+
return
435+
}
436+
437+
last, seen := transport.lastPacketTime[id]
438+
transport.lastPacketTime[id] = timestamp
439+
if !seen {
440+
return
441+
}
442+
443+
interval := timestamp.Sub(last)
444+
if interval <= transport.maxPacketInterval {
445+
return
446+
}
447+
448+
transport.logger.Warn().
449+
Uint16("id", uint16(id)).
450+
Dur("interval", interval).
451+
Dur("threshold", transport.maxPacketInterval).
452+
Msg("packet interval exceeded, propagating fault")
453+
transport.SendFault()
454+
}
455+
424456
// handleConversation is called when the sniffer detects a new conversation and handles its specific packets
425457
func (transport *Transport) handleConversation(socket network.Socket, reader io.Reader) {
426458
srcAddr := fmt.Sprintf("%s:%d", socket.SrcIP, socket.SrcPort)
@@ -473,3 +505,10 @@ func (transport *Transport) SendFault() {
473505
func (transport *Transport) SetpropagateFault(enabled bool) {
474506
transport.propagateFault = enabled
475507
}
508+
509+
// SetMaxPacketInterval sets the maximum allowed interval between two
510+
// consecutive UDP packets of the same id before a fault is propagated.
511+
// A non-positive interval disables the check.
512+
func (transport *Transport) SetMaxPacketInterval(interval time.Duration) {
513+
transport.maxPacketInterval = interval
514+
}

0 commit comments

Comments
 (0)