@@ -31,7 +31,7 @@ type Transport struct {
3131 decoder * presentation.Decoder
3232 encoder * presentation.Encoder
3333
34- connectionsMx * sync.Mutex
34+ connectionsMx * sync.RWMutex
3535 connections map [abstraction.TransportTarget ]net.Conn
3636
3737 ipToTarget map [string ]abstraction.TransportTarget
@@ -45,22 +45,27 @@ type Transport struct {
4545
4646 logger zerolog.Logger
4747
48+ byteReaderPool sync.Pool
49+
4850 errChan chan error
4951}
5052
53+ // For tests
54+ var zeroTime time.Time
55+
5156// HandleClient connects to the specified client and handles its messages. This method blocks.
5257// This method will continuously try to reconnect to the client if it disconnects,
5358// applying exponential backoff between attempts.
5459func (transport * Transport ) HandleClient (config tcp.ClientConfig , remote string ) error {
5560 client := tcp .NewClient (remote , config , transport .logger )
56- defer transport .logger .Warn ().Str ("remoteAddress" , remote ).Msg ("abort connection" )
61+ clientLogger := transport .logger .With ().Str ("remoteAddress" , remote ).Logger ()
62+ defer clientLogger .Warn ().Msg ("abort connection" )
5763 var hasConnected = false
5864
5965 for {
6066 conn , err := client .Dial ()
6167 if err != nil {
62- transport .logger .Debug ().Stack ().Err (err ).Str ("remoteAddress" , remote ).Msg ("dial failed" )
63-
68+ clientLogger .Debug ().Stack ().Err (err ).Msg ("dial failed" )
6469 // Only return if reconnection is disabled
6570 if ! config .TryReconnect {
6671 if hasConnected {
@@ -73,7 +78,7 @@ func (transport *Transport) HandleClient(config tcp.ClientConfig, remote string)
7378 // For ErrTooManyRetries, we still want to continue retrying
7479 // The client will reset its retry counter on the next Dial() call
7580 if _ , ok := err .(tcp.ErrTooManyRetries ); ok {
76- transport . logger . Warn (). Str ( "remoteAddress" , remote ).Msg ("reached max retries, will continue attempting to reconnect" )
81+ clientLogger . Warn ().Msg ("reached max retries, will continue attempting to reconnect" )
7782 // Add a longer delay before restarting the retry cycle
7883 time .Sleep (config .ConnectionBackoffFunction (config .MaxConnectionRetries ))
7984 }
@@ -85,12 +90,12 @@ func (transport *Transport) HandleClient(config tcp.ClientConfig, remote string)
8590
8691 err = transport .handleTCPConn (conn )
8792 if errors .Is (err , error (ErrTargetAlreadyConnected {})) {
88- transport . logger . Warn ().Stack ().Err (err ). Str ( "remoteAddress" , remote ).Msg ("multiple connections for same target" )
93+ clientLogger . Warn ().Stack ().Err (err ).Msg ("multiple connections for same target" )
8994 transport .errChan <- err
9095 return err
9196 }
9297 if err != nil {
93- transport . logger . Debug ().Stack ().Err (err ). Str ( "remoteAddress" , remote ).Msg ("connection lost" )
98+ clientLogger . Debug ().Stack ().Err (err ).Msg ("connection lost" )
9499 if ! config .TryReconnect {
95100 transport .SendFault ()
96101 transport .errChan <- err
@@ -254,6 +259,10 @@ func (transport *Transport) readLoopTCPConn(conn net.Conn, logger zerolog.Logger
254259
255260 logger .Trace ().Type ("type" , packet ).Msg ("packet" )
256261 transport .api .Notification (NewPacketNotification (packet , from , to , time .Now ()))
262+
263+ if dataPacket , ok := packet .(* data.Packet ); ok {
264+ data .ReleasePacket (dataPacket )
265+ }
257266 }
258267 }()
259268}
@@ -289,30 +298,31 @@ func (transport *Transport) handlePacketEvent(message PacketMessage) error {
289298
290299 if message .Id () == 0 {
291300 eventLogger .Info ().Msg ("broadcasting packet id 0" )
292- data , err := transport .encoder .Encode (message .Packet )
301+ buf , err := transport .encoder .Encode (message .Packet )
293302 if err != nil {
294303 eventLogger .Error ().Stack ().Err (err ).Msg ("encode" )
295304 transport .errChan <- err
296305 return err
297306 }
307+ defer transport .encoder .ReleaseBuffer (buf )
308+ data := buf .Bytes ()
298309
299- transport .connectionsMx .Lock ()
300- defer transport .connectionsMx .Unlock ()
310+ transport .connectionsMx .RLock ()
311+ defer transport .connectionsMx .RUnlock ()
301312 for target , conn := range transport .connections {
302- eventLogger := eventLogger .With ().Str ("target" , string (target )).Logger ()
303-
313+ targetName := string (target )
304314 totalWritten := 0
305315 for totalWritten < len (data ) {
306316 n , err := conn .Write (data [totalWritten :])
307- eventLogger .Trace ().Int ("amount" , n ).Msg ("written chunk" )
317+ eventLogger .Trace ().Str ( "target" , targetName ). Int ("amount" , n ).Msg ("written chunk" )
308318 totalWritten += n
309319 if err != nil {
310- eventLogger .Error ().Stack ().Err (err ).Msg ("write" )
320+ eventLogger .Error ().Str ( "target" , targetName ). Stack ().Err (err ).Msg ("write" )
311321 transport .errChan <- err
312322 return err
313323 }
314324 }
315- eventLogger .Info ().Msg ("sent" )
325+ eventLogger .Info ().Str ( "target" , targetName ). Msg ("sent" )
316326 }
317327 return nil
318328 }
@@ -328,11 +338,11 @@ func (transport *Transport) handlePacketEvent(message PacketMessage) error {
328338 eventLogger .Info ().Msg ("sending" )
329339
330340 conn , err := func () (net.Conn , error ) {
331- transport .connectionsMx .Lock ()
332- defer transport .connectionsMx .Unlock ()
341+ transport .connectionsMx .RLock ()
342+ defer transport .connectionsMx .RUnlock ()
333343 conn , ok := transport .connections [target ]
334344 if ! ok {
335- eventLogger .Warn ().Msg ("target not connected" )
345+ eventLogger .Warn ().Msg ("target not connected" )
336346
337347 err := ErrConnClosed {Target : target }
338348 return nil , err
@@ -344,12 +354,14 @@ func (transport *Transport) handlePacketEvent(message PacketMessage) error {
344354 return err
345355 }
346356
347- data , err := transport .encoder .Encode (message .Packet )
357+ buf , err := transport .encoder .Encode (message .Packet )
348358 if err != nil {
349359 eventLogger .Error ().Stack ().Err (err ).Msg ("encode" )
350360 transport .errChan <- err
351361 return err
352362 }
363+ defer transport .encoder .ReleaseBuffer (buf )
364+ data := buf .Bytes ()
353365
354366 totalWritten := 0
355367 for totalWritten < len (data ) {
@@ -413,14 +425,30 @@ func (transport *Transport) HandleUDPServer(server *udp.Server) {
413425 }
414426}
415427
428+ func (transport * Transport ) replicateFault (packet abstraction.Packet , logger zerolog.Logger ) {
429+ logger .Info ().Msg ("replicating packet with id 0 to all boards" )
430+ err := transport .handlePacketEvent (NewPacketMessage (packet ))
431+ if err != nil {
432+ logger .Error ().Err (err ).Msg ("failed to replicate packet" )
433+ }
434+ }
435+
416436// handleUDPPacket handles a single UDP packet received by the UDP server
417437func (transport * Transport ) handleUDPPacket (udpPacket udp.Packet ) {
418438 srcAddr := fmt .Sprintf ("%s:%d" , udpPacket .SourceIP , udpPacket .SourcePort )
419439 dstAddr := fmt .Sprintf ("%s:%d" , udpPacket .DestIP , udpPacket .DestPort )
420440
421441 // Create a reader from the payload
422- reader := bytes .NewReader (udpPacket .Payload )
423-
442+ readerAny := transport .byteReaderPool .Get ()
443+ var reader * bytes.Reader
444+ if readerAny != nil {
445+ reader = readerAny .(* bytes.Reader )
446+ reader .Reset (udpPacket .Payload )
447+ } else {
448+ reader = bytes .NewReader (udpPacket .Payload )
449+ }
450+ defer transport .byteReaderPool .Put (reader )
451+
424452 // Decode the packet
425453 packet , err := transport .decoder .DecodeNext (reader )
426454 if err != nil {
@@ -435,15 +463,15 @@ func (transport *Transport) handleUDPPacket(udpPacket udp.Packet) {
435463
436464 // Intercept packets with id == 0 and replicate
437465 if transport .propagateFault && packet .Id () == 0 {
438- transport .logger .Info ().Msg ("replicating packet with id 0 to all boards" )
439- err := transport .handlePacketEvent (NewPacketMessage (packet ))
440- if err != nil {
441- transport .logger .Error ().Err (err ).Msg ("failed to replicate packet" )
442- }
466+ transport .replicateFault (packet , transport .logger )
443467 }
444468
445469 // Send notification
446470 transport .api .Notification (NewPacketNotification (packet , srcAddr , dstAddr , udpPacket .Timestamp ))
471+
472+ if dataPacket , ok := packet .(* data.Packet ); ok {
473+ data .ReleasePacket (dataPacket )
474+ }
447475}
448476
449477// handleConversation is called when the sniffer detects a new conversation and handles its specific packets
@@ -463,14 +491,15 @@ func (transport *Transport) handleConversation(socket network.Socket, reader io.
463491
464492 // Intercept packets with id == 0 and replicate
465493 if transport .propagateFault && packet .Id () == 0 {
466- conversationLogger .Info ().Msg ("replicating packet with id 0 to all boards" )
467- err := transport .handlePacketEvent (NewPacketMessage (packet ))
468- if err != nil {
469- conversationLogger .Error ().Err (err ).Msg ("failed to replicate packet" )
470- }
494+ transport .replicateFault (packet , transport .logger )
471495 }
472496
497+ // Send notification
473498 transport .api .Notification (NewPacketNotification (packet , srcAddr , dstAddr , time .Now ()))
499+
500+ if dataPacket , ok := packet .(* data.Packet ); ok {
501+ data .ReleasePacket (dataPacket )
502+ }
474503 }
475504 }()
476505}
0 commit comments