@@ -34,16 +34,38 @@ type Server struct {
3434 count int
3535 ringMutex sync.Mutex
3636 notEmpty * sync.Cond
37+
38+ lastSeen map [string ]time.Time
39+ lastSeenMu sync.Mutex
40+ keepAliveCheckInterval time.Duration
41+ keepAliveTimeout time.Duration
42+ OnDisconnect func ()
3743}
3844
39- func NewServer (address string , port uint16 , logger * zerolog.Logger , ringBufferSize int , packetChanSize int ) * Server {
45+ const (
46+ defaultKeepAliveCheckInterval = 5 * time .Millisecond
47+ defaultKeepAliveTimeout = 100 * time .Millisecond
48+ )
49+
50+ func NewServer (address string , port uint16 , logger * zerolog.Logger , ringBufferSize int , packetChanSize int , keepAliveCheckInterval time.Duration , keepAliveTimeout time.Duration , onDisconnect func ()) * Server {
51+ if keepAliveCheckInterval <= 0 {
52+ keepAliveCheckInterval = defaultKeepAliveCheckInterval
53+ }
54+ if keepAliveTimeout <= 0 {
55+ keepAliveTimeout = defaultKeepAliveTimeout
56+ }
57+
4058 s := & Server {
41- address : address ,
42- port : port ,
43- logger : logger ,
44- packetsCh : make (chan Packet , packetChanSize ),
45- errorsCh : make (chan error , 100 ),
46- stopCh : make (chan struct {}),
59+ address : address ,
60+ port : port ,
61+ logger : logger ,
62+ packetsCh : make (chan Packet , packetChanSize ),
63+ errorsCh : make (chan error , 100 ),
64+ stopCh : make (chan struct {}),
65+ lastSeen : make (map [string ]time.Time ),
66+ keepAliveCheckInterval : keepAliveCheckInterval ,
67+ keepAliveTimeout : keepAliveTimeout ,
68+ OnDisconnect : onDisconnect ,
4769 }
4870
4971 s .ring = make ([]Packet , ringBufferSize )
@@ -71,8 +93,9 @@ func (s *Server) Start() error {
7193 Uint16 ("port" , s .port ).
7294 Msg ("UDP server started" )
7395
74- go s .readLoop ()
75- go s .dispatchLoop ()
96+ go s .readLoop () // Read incoming UDP packets
97+ go s .dispatchLoop () // Dispatch packets from ring buffer to channel
98+ go s .keepAliveLoop () // Monitor keep-alive timeouts
7699 return nil
77100}
78101
@@ -121,12 +144,51 @@ func (s *Server) readLoop() {
121144 Int ("size" , len (payload )).
122145 Msg ("received UDP packet" )
123146
147+ // Update keep-alive tracking for this source IP
148+ s .lastSeenMu .Lock ()
149+ s .lastSeen [addr .IP .String ()] = packet .Timestamp
150+ s .lastSeenMu .Unlock ()
151+
124152 // Push packet to ring buffer
125153 s .push (packet )
126154 }
127155 }
128156}
129157
158+ // keepAliveLoop checks for clients that have not sent any packets within the keepAliveTimeout duration.
159+ func (s * Server ) keepAliveLoop () {
160+ ticker := time .NewTicker (s .keepAliveCheckInterval )
161+ defer ticker .Stop ()
162+
163+ for {
164+ select {
165+ case <- s .stopCh :
166+ return
167+ case now := <- ticker .C :
168+ var timedOut []string
169+
170+ s .lastSeenMu .Lock ()
171+ for ip , last := range s .lastSeen {
172+ if now .Sub (last ) > s .keepAliveTimeout {
173+ timedOut = append (timedOut , ip )
174+ delete (s .lastSeen , ip )
175+ }
176+ }
177+ s .lastSeenMu .Unlock ()
178+
179+ for _ , ip := range timedOut {
180+ s .logger .Error ().
181+ Str ("ip" , ip ).
182+ Dur ("timeout" , s .keepAliveTimeout ).
183+ Msg ("keep-alive timeout: no UDP packets received" )
184+ if s .OnDisconnect != nil {
185+ s .OnDisconnect ()
186+ }
187+ }
188+ }
189+ }
190+ }
191+
130192func (s * Server ) GetPackets () <- chan Packet {
131193 return s .packetsCh
132194}
0 commit comments