My project needs to do IPC by using Netlink and the reference is Netlink unicast. I had done some changes in code. Firstly, I started both receiver and sender, then I inputted the sender's pid to receiver and later inputted receiver's pid to sender. But the receiver didn't receive the message. I also refer Is anyone using netlink for IPC?, none of them were working. Is that any problem in my code?
Receiver's code:
#include <sys/socket.h>
#include <linux/netlink.h>
#include <stdio.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#define NLINK_MSG_LEN 1024
#define NETLINK_USER 31
int main() {
int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
//int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
//int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
printf("Inside recv main\n");
if (fd < 0) {
printf("Socket creation failed. try again\n");
return -1;
}
/* Declare for src NL sockaddr, dest NL sockaddr, nlmsghdr, iov, msghr */
struct sockaddr_nl src_addr, dest_addr;
memset(&src_addr, 0, sizeof(src_addr));
memset(&dest_addr, 0, sizeof(dest_addr));
//allocate buffer for netlink message which is message header + message payload
struct nlmsghdr *nlh =(struct nlmsghdr *) malloc(NLMSG_SPACE(NLINK_MSG_LEN));
memset(nlh, 0, NLMSG_SPACE(NLINK_MSG_LEN));
//fill the iovec structure
struct iovec iov;
memset(&iov, 0, sizeof(iov));
//define the message header for message
//sending
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
int sender_pid;
printf("Receiver process id: %d\n", getpid());
printf("Sender process id: ");
scanf("%d", &sender_pid);
src_addr.nl_family = AF_NETLINK; //AF_NETLINK socket protocol
src_addr.nl_pid = getpid(); //application unique id
src_addr.nl_groups = 0; //specify not a multicast communication
dest_addr.nl_family = AF_NETLINK; // protocol family
dest_addr.nl_pid = sender_pid; //destination process id
dest_addr.nl_groups = 0;
nlh->nlmsg_len = NLMSG_SPACE(NLINK_MSG_LEN); //netlink message length
nlh->nlmsg_pid = getpid(); //src application unique id
nlh->nlmsg_flags = 0;
iov.iov_base = (void *)nlh; //netlink message header base address
iov.iov_len = nlh->nlmsg_len; //netlink message length
msg.msg_name = (void *)&dest_addr;
msg.msg_namelen = sizeof(dest_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
//attach socket to unique id or address
if(bind(fd, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0) {
printf("Bind failed");
return -1;
}
/* Listen forever in a while loop */
while (1) {
//receive the message
recvmsg(fd, &msg, 0);
printf("Received message: %s\n", (char *)NLMSG_DATA(nlh));
}
close(fd); // close the socket
}
Sender's code:
#include <sys/socket.h>
#include <linux/netlink.h>
#include <stdio.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#define NLINK_MSG_LEN 1024
#define NETLINK_USER 31
int main() {
int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
//int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK);
//int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
printf("Inside send main\n");
if (fd < 0) {
printf("Socket creation failed. try again\n");
return -1;
}
/* Declare for src NL sockaddr, dest NL sockaddr, nlmsghdr, iov, msghr */
struct sockaddr_nl src_addr, dest_addr;
memset(&src_addr, 0, sizeof(src_addr));
memset(&dest_addr, 0, sizeof(dest_addr));
//allocate buffer for netlink message which is message header + message payload
struct nlmsghdr *nlh =(struct nlmsghdr *) malloc(NLMSG_SPACE(NLINK_MSG_LEN));
memset(nlh, 0, NLMSG_SPACE(NLINK_MSG_LEN));
//fill the iovec structure
struct iovec iov;
memset(&iov, 0, sizeof(iov));
//define the message header for message
//sending
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
int receiver_pid;
printf("Sender process id: %d\n", getpid());
printf("Receiver process id: ");
scanf("%d", &receiver_pid);
src_addr.nl_family = AF_NETLINK; //AF_NETLINK socket protocol
src_addr.nl_pid = getpid(); //application unique id
src_addr.nl_groups = 0; //specify not a multicast communication
dest_addr.nl_family = AF_NETLINK; // protocol family
dest_addr.nl_pid = receiver_pid; //destination process id
dest_addr.nl_groups = 0;
nlh->nlmsg_len = NLMSG_SPACE(NLINK_MSG_LEN); //netlink message length
nlh->nlmsg_pid = getpid(); //src application unique id
nlh->nlmsg_flags = 0;
strcpy(NLMSG_DATA(nlh), "Hello World !"); //copy the payload to be sent
iov.iov_base = (void *)nlh; //netlink message header base address
iov.iov_len = nlh->nlmsg_len; //netlink message length
msg.msg_name = (void *)&dest_addr;
msg.msg_namelen = sizeof(dest_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
//attach socket to unique id or address
if(bind(fd, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0) {
printf("Bind failed");
return -1;
}
//send the message
sendmsg(fd, &msg, 0);
printf("Send message %s\n", (char *)NLMSG_DATA(nlh));
close(fd); // close the socket
}
You are using the wrong kind of protocol to socket
. The only one which can do what you want, IPC between user-space processes, is NETLINK_USERSOCK
.
Bear in mind that in the way you are arranging communication with PIDs, you might miss some messages... For the purposes of verifying the communication does happen, you can leave msg_name
NULL
for the receiver and that will have no ill effect(s) - doing so & changing protocol, your code works as expected.