@@ -632,6 +632,10 @@ type NetlinkSocket struct {
632
632
fd int32
633
633
lsa unix.SockaddrNetlink
634
634
sync.Mutex
635
+
636
+ // pfd is non nil when the socket is in non-blocking mode, and is used to wait for events on the socket.
637
+ pfd * unix.PollFd
638
+ pollTimeout int64
635
639
}
636
640
637
641
func getNetlinkSocket (protocol int ) (* NetlinkSocket , error ) {
@@ -728,17 +732,22 @@ func Subscribe(protocol int, groups ...uint) (*NetlinkSocket, error) {
728
732
return nil , err
729
733
}
730
734
735
+ var pfd * unix.PollFd
731
736
// Sometimes (socket_linux.go:SocketGet), Subscribe is used to create a socket
732
- // that subscirbed to no groups. So we don't need to set nonblock there.
737
+ // that subscribes to no groups. So we don't need to set nonblock there.
733
738
if len (groups ) > 0 {
734
739
if err := unix .SetNonblock (fd , true ); err != nil {
735
740
unix .Close (fd )
736
741
return nil , err
737
742
}
743
+ pfd = & unix.PollFd {Fd : int32 (fd ), Events : unix .POLLIN }
738
744
}
739
745
740
746
s := & NetlinkSocket {
741
- fd : int32 (fd ),
747
+ fd : int32 (fd ),
748
+ pfd : pfd ,
749
+ // poll blocks infinitely by default.
750
+ pollTimeout : - 1 ,
742
751
}
743
752
s .lsa .Family = unix .AF_NETLINK
744
753
@@ -791,6 +800,13 @@ func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, *unix.SockaddrNetli
791
800
if fd < 0 {
792
801
return nil , nil , fmt .Errorf ("Receive called on a closed socket" )
793
802
}
803
+ // The socket is in non-blocking mode.
804
+ if s .pfd != nil {
805
+ if _ , err := unix .Poll ([]unix.PollFd {* s .pfd }, int (atomic .LoadInt64 (& s .pollTimeout ))); err != nil {
806
+ return nil , nil , fmt .Errorf ("Error polling the socket: %w" , err )
807
+ }
808
+ }
809
+
794
810
var fromAddr * unix.SockaddrNetlink
795
811
var rb [RECEIVE_BUFFER_SIZE ]byte
796
812
nr , from , err := unix .Recvfrom (fd , rb [:], 0 )
@@ -825,7 +841,12 @@ func (s *NetlinkSocket) SetSendTimeout(timeout *unix.Timeval) error {
825
841
func (s * NetlinkSocket ) SetReceiveTimeout (timeout * unix.Timeval ) error {
826
842
// Set a read timeout of SOCKET_READ_TIMEOUT, this will allow the Read to periodically unblock and avoid that a routine
827
843
// remains stuck on a recvmsg on a closed fd
828
- return unix .SetsockoptTimeval (int (s .fd ), unix .SOL_SOCKET , unix .SO_RCVTIMEO , timeout )
844
+ if err := unix .SetsockoptTimeval (int (s .fd ), unix .SOL_SOCKET , unix .SO_RCVTIMEO , timeout ); err != nil {
845
+ return err
846
+ }
847
+ // Set poll timeout to the same value to allow it to unblock upon timeout.
848
+ atomic .StoreInt64 (& s .pollTimeout , timeout .Sec * 1000 + timeout .Usec / 1000 )
849
+ return nil
829
850
}
830
851
831
852
// SetReceiveBufferSize allows to set a receive buffer size on the socket
0 commit comments