0

I am writing NETLINK xfrm socket programming to create association and policies for ESP communication. To send the data to kernel

sockfd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_XFRM);
setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sckbuff, sizeof(sckbuff));
setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &sckbuff, sizeof(sckbuff));
bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_nl));
...
memset(&msg, 0, sizeof(struct msghdr));
msg.msg_name = (void *)&(addr);
msg.msg_namelen = sizeof(addr);
...
memset(&iov, 0, sizeof(struct iovec));
iov.iov_base = (void *)netlink_req;
iov.iov_len = netlink_req->nlmsg_len;

msg.msg_iov = &iov;
msg.msg_iovlen = 1;

sendmsg(sockfd, &msg, 0);

And to receive the response from kernel

while(true)
{
  ...
  FD_ZERO(&readfds);
  FD_SET(sockfd, &readfds);
  select(sockfd+1, &readfds, NULL, NULL, NULL);

  read_len = recvmsg(sockfd, &msg, MSG_PEEK);
  printf("Data received %d\n", read_len);
  for (nh = (struct nlmsghdr *) buf;
     NLMSG_OK (nh, read_len);
     nh = NLMSG_NEXT (nh, read_len))
  {
    if (nh->nlmsg_type == NLMSG_DONE)
    {
          break;
    }
    else if (nh->nlmsg_type == NLMSG_ERROR)
    {
      ...
    }
    ...
  }
}
...

It is working file if recvmsg is done sequentially without select.

But when i tried to send multiple request and do select with sockfd in another thread then recvmsg continue to receive the same message and never stop.

Is there any flag i need to set in response to stop the continuous loop or any other way?

soni
  • 77
  • 1
  • 9
  • 1
    Please, share the code with `select`, since it is the code you are having issues with. – Roberto Caboni Jan 25 '21 at 14:55
  • @RobertoCaboni, Hi i have updated the code with `select`. Code is continuously printing the line `Data received 32` with same data – soni Jan 26 '21 at 06:55
  • 3
    You're using `MSG_PEEK`, which doesn't dequeue data. Why wouldn't it give the same result? (Also, if you're using select, check the actual returned value (return and set contents)) – Hasturkun Jan 26 '21 at 09:55
  • @Hasturkun nice catch. Would you expand your comment into an answer? – Roberto Caboni Jan 26 '21 at 10:49

1 Answers1

2

recvmsg(), when called with the MSG_PEEK flag, returns data but doesn't remove it from the socket's receive queue, leading to the next receive returning the same data again.

Remove the flag (or perform a second call for the same size without it) to ensure you get the following messages.

I'd also highly recommend checking the return from select() as well as the updated set (since select() can return without a readable socket in this case, e.g. if a signal is caught). I'd also note that in your current usage, select() isn't giving you much over a plain blocking recvmsg() call.

Hasturkun
  • 35,395
  • 6
  • 71
  • 104