Move flags to recvmsg function in netlink

netlink_multicast used 3 calls to fcntl in order to set O_NONBLOCK on
socket. It is possible to pass MSG_DONTWAIT flag just to recvmsg function,
without setting it permanently on socket. Save few kernel calls and use
recvmsg flags.

It is supported since kernel 2.2, should be fine for any device still
receiving updates.
This commit is contained in:
Petr Menšík
2021-03-02 21:36:45 +00:00
committed by Simon Kelley
parent 9e147480ed
commit 8b8a4148ec

View File

@@ -102,7 +102,7 @@ char *netlink_init(void)
return NULL; return NULL;
} }
static ssize_t netlink_recv(void) static ssize_t netlink_recv(int flags)
{ {
struct msghdr msg; struct msghdr msg;
struct sockaddr_nl nladdr; struct sockaddr_nl nladdr;
@@ -118,7 +118,8 @@ static ssize_t netlink_recv(void)
msg.msg_iovlen = 1; msg.msg_iovlen = 1;
msg.msg_flags = 0; msg.msg_flags = 0;
while ((rc = recvmsg(daemon->netlinkfd, &msg, MSG_PEEK | MSG_TRUNC)) == -1 && errno == EINTR); while ((rc = recvmsg(daemon->netlinkfd, &msg, flags | MSG_PEEK | MSG_TRUNC)) == -1 &&
errno == EINTR);
/* make buffer big enough */ /* make buffer big enough */
if (rc != -1 && (msg.msg_flags & MSG_TRUNC)) if (rc != -1 && (msg.msg_flags & MSG_TRUNC))
@@ -135,7 +136,7 @@ static ssize_t netlink_recv(void)
/* read it for real */ /* read it for real */
msg.msg_flags = 0; msg.msg_flags = 0;
while ((rc = recvmsg(daemon->netlinkfd, &msg, 0)) == -1 && errno == EINTR); while ((rc = recvmsg(daemon->netlinkfd, &msg, flags)) == -1 && errno == EINTR);
/* Make sure this is from the kernel */ /* Make sure this is from the kernel */
if (rc == -1 || nladdr.nl_pid == 0) if (rc == -1 || nladdr.nl_pid == 0)
@@ -198,7 +199,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
while (1) while (1)
{ {
if ((len = netlink_recv()) == -1) if ((len = netlink_recv(0)) == -1)
{ {
if (errno == ENOBUFS) if (errno == ENOBUFS)
{ {
@@ -350,22 +351,14 @@ static void nl_multicast_state(unsigned state)
{ {
ssize_t len; ssize_t len;
struct nlmsghdr *h; struct nlmsghdr *h;
int flags;
if ((flags = fcntl(daemon->netlinkfd, F_GETFL)) == -1 ||
fcntl(daemon->netlinkfd, F_SETFL, flags | O_NONBLOCK) == -1)
return;
do { do {
/* don't risk blocking reading netlink messages here. */ /* don't risk blocking reading netlink messages here. */
while ((len = netlink_recv()) != -1) while ((len = netlink_recv(MSG_DONTWAIT)) != -1)
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len)) for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
state = nl_async(h, state); state = nl_async(h, state);
} while (errno == ENOBUFS); } while (errno == ENOBUFS);
/* restore non-blocking status */
fcntl(daemon->netlinkfd, F_SETFL, flags);
} }
void netlink_multicast(void) void netlink_multicast(void)