Does libevent support netlink socket - linux

I use netlink to receive an interrupt number from kernel. The application in user space uses libevent to handle TCP/IP request and netlink message. Does libevent support Linux netlink socket? I will appreciate for a simple example.

Yes, libevent supports netlink socket.
There is https://github.com/libevent/libevent/blob/master/sample/hello-world.c, it is modified below to listen to netlink socket.
The basic example listens to Linux network interface creation/deletion and can be executed with sudo to gain privilege needed. It listens to same events as ip monitor link.
Another example of listening to RAW sockets with libevent is here https://github.com/bodgit/libevent-natpmp/blob/master/natpmp.c.
static void link_recvmsg(int fd, short event, void *arg)
{
char buf[NLMSG_SPACE(BUF_SIZE)] = {0};
socklen_t socklen;
struct iovec iov = {.iov_base = buf, .iov_len = sizeof(buf)};
struct sockaddr addr;
memset(&addr, 0, sizeof(struct sockaddr));
if (!fd || -1 == fd)
return;
int status = getsockname(fd, &addr, &socklen);
if(-1 == status)
return;
struct msghdr mh = {.msg_name = NULL, .msg_namelen = 0, .msg_iov = &iov, .msg_iovlen = 1,
.msg_flags = 0, .msg_name = &addr, .msg_namelen = sizeof(struct sockaddr)};
status = recvmsg(fd, &mh, 0);
if ((-1 == status) && ((EINTR == errno) || (EAGAIN == errno)))
return;
if(-1 == status)
return;
if ((mh.msg_flags & MSG_TRUNC) == MSG_TRUNC)
return;
if ((mh.msg_flags & MSG_CTRUNC) == MSG_CTRUNC)
return;
for (const struct nlmsghdr *h = (struct nlmsghdr *)buf; NLMSG_OK(h, status); h = NLMSG_NEXT(h, status)) {
switch (h->nlmsg_type) {
case RTM_NEWLINK:
fprintf(stderr, "got RTM_NEWLINK\n");
break;
case RTM_DELLINK:
fprintf(stderr, "got RTM_DELLINK\n");
break;
default:
fprintf(stderr, "unexpected case in swtch statement\n");
break;
}
}
}
int main(int argc, char **argv)
{
/* some init code here */
/* NETLINK socket */
int status;
int buf_size = BUF_SIZE;
struct sockaddr_nl src_addr;
int socket_nl = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, NETLINK_ROUTE);
if(-1 == socket_nl) return -1;
memset(&src_addr, 0, sizeof(struct sockaddr_nl));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid();
src_addr.nl_groups |= RTNLGRP_LINK;
status = setsockopt(socket_nl, SOL_SOCKET, SO_RCVBUF,
&buf_size, sizeof(buf_size));
if(-1 == status) return -1;
status = bind(socket_nl, (struct sockaddr *)&src_addr, sizeof(struct sockaddr_nl));
if(status < 0) return -1;
static struct event nl_ev;
event_set(&nl_ev, socket_nl, EV_READ|EV_PERSIST, link_recvmsg,
NULL);
if (base) {
event_base_set(base, &nl_ev);
}
event_add(&nl_ev, NULL);
/* some other code, dispatch event and deinit */
}

Related

client socket connection issue

Hi I'm trying to write a client application which will try to connect a remote server. If it can not connect to the server, it will try once again after 5 seconds. If the socket is closed somehow, it will try to connect once again.
I'm getting an error like connect: Transport endpoint is already connected
What could be the problem ?
static void sig_chld(int signo)
{
pid_t pid;
int stat;
while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);
return;
}
int main(int argc, char *argv[])
{
int sockfd, numbytes;
char buf[MAXDATASIZE];
pid_t childpid;
struct hostent *he;
struct sockaddr_in their_addr; /* connector's address information */
if ((he=gethostbyname(argv[1])) == NULL) { /* get the host info */
herror("gethostbyname");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
their_addr.sin_family = AF_INET; /* host byte order */
their_addr.sin_port = htons(PORT); /* short, network byte order */
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(their_addr.sin_zero), 8); /* zero the rest of the struct */
for ( ; ; ) {
while (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1)
{
perror("connect");
sleep(5);
}
if ( (childpid = fork()) == 0)
{ /* child process */
while(1)
{
if (send(sockfd, "Hello, world!\n", 14, 0) == -1)
{
perror("send");
}
sleep(3);
}
close(sockfd);
}
}
return 0;
}
You can't reconnect a socket once you have even tried to connect it before, even if it failed. You have to close it and create a new one.

How to add a new custom layer 4 protocol (a new Raw socket) in linux kernel?

i am trying adding my own customized layer 4 protocol in linux (ubuntu 14.04) - IPPROTO_MYPROTO as a loadable kernel module. I have done all necessary steps to register the protocol. Here i am sharing my code.
When i am trying to send a mesage from user space program using sendmsg(), i expect the corresponding fn myproto_sendmsg() registered via struct proto structure should be called in kernel space. But what i am observing is that though the myproto_sendmsg() in kernel space is not being called, yet destination machine is receiving the correct data. surprise ! surprise !. Is the default udp sendmsg() fn kicking in here which is like uninvited guest doing his work.
Here, sendmsg() call in user space returns as many bytes as send. Hence, fn returns success.
User space program :
void forwardUDP( int destination_node ,char sendString[] )
{
struct msghdr msg;
destination_node = destination_node % N; //destination node to which data is to be forwaded
int sock, rc;
struct sockaddr_in server_addr;
struct iovec iov;
struct hostent *host; //hostent predefined structure use to store info about host
host = (struct hostent *) gethostbyname(node[destination_node].ip_address);//gethostbyname returns a pointer to hostent
if ((sock = socket(AF_INET, SOCK_RAW, 5)) == -1)
{
perror("socket");
exit(1);
}
//destination address structure
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(node[destination_node].udpportno);
server_addr.sin_addr = *((struct in_addr *)host->h_addr); //host->h_addr gives address of host
bzero(&(server_addr.sin_zero),8);
/* fill the messsage structure*/
memset(&msg, 0 , sizeof(struct msghdr));
memset(&iov, 0, sizeof(struct iovec));
msg.msg_name = (void *)&server_addr;
msg.msg_namelen = sizeof(struct sockaddr_in);
printf("sendString = %s\n", sendString);
iov.iov_base = (void *)sendString;
iov.iov_len = strlen(sendString);
msg.msg_iov = &iov;
printf("len = %d\n", strlen(sendString));
#if 1
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
#endif
//sendto(sock, sendString, strlen(sendString), 0,(struct sockaddr *)&server_addr, sizeof(struct sockaddr));
**rc = sendmsg(sock, &msg, 0);**
printf("rc = %d\n", rc);
//sendto() function shall send a message through a connectionless-mode socket.
printf("\nFORWARD REQUEST : '%s' has been forwarded to node ---->%d\n",sendString,destination_node);
//close(sock);
}
Kernel Module
/* Define the handler which will recieve all ingress packets for protocol = IPPROTO_MYPROTO
defined in net/protocol.h
*/
/* Resgiter the call backs for pkt reception */
static const struct net_protocol myproto_protocol = {
.handler = myproto_rcv,
.err_handler = myproto_err,
.no_policy = 1,
.netns_ok = 1,
};
static struct inet_protosw myproto_protosw;
int
myproto_rcv(struct sk_buff *skb){
printk(KERN_INFO "myproto_rcv is called\n");
return 0;
}
int
myproto_sendmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg, size_t len){
printk(KERN_INFO "myproto_sendmsg() is called\n");
return 0;
}
void myproto_lib_close(struct sock *sk, long timeout){
printk(KERN_INFO "close is called\n");
return;
}
int
myproto_recvmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg,
size_t len, int noblock, int flags,
int *addr_len){
printk(KERN_INFO "myproto_recvmsg() is called.\n");
printk(KERN_INFO "iocb = 0x%x,\nsk = 0x%x,\nmsg = 0x%x,\nlen = %d,\nnoblock = %d,\nflags = %d,\naddr_len = 0x%x", iocb, sk, msg, len, noblock, flags, addr_len);
return 0;
}
/* Socket structure for Custom protocol, see struct udp_sock for example*/
struct myproto_sock{
struct inet_sock inet; // should be first member
__u16 len;
};
void
myproto_lib_hash(struct sock *sk){
printk(KERN_INFO "myproto_lib_hash() is called");
}
/* Define the **struct proto** structure for the Custom protocol defined in
net/sock.h */
struct proto myproto_prot = {
.name = "MYPROTO",
.owner = THIS_MODULE,
.close = myproto_lib_close,
.sendmsg = myproto_sendmsg,
.hash = myproto_lib_hash,
.recvmsg = myproto_recvmsg,
.obj_size = sizeof(struct myproto_sock),
.slab_flags = SLAB_DESTROY_BY_RCU,
};
int init_module(void);
void cleanup_module(void);
int
init_module(void)
{
int rc = 0;
rc = proto_register(&myproto_prot, 1);
if(rc == 0){
printk(KERN_INFO "Protocol registration is successful\n");
}
else{
printk(KERN_INFO "Protocol registration is failed\n");
cleanup_module();
return rc;
}
rc = inet_add_protocol(&myproto_protocol, IPPROTO_MYPROTO);
if(rc == 0){
printk(KERN_INFO "Protocol insertion in inet_protos[] is successful\n");
}
else{
printk(KERN_INFO "Protocol insertion in inet_protos[] is failed\n");
cleanup_module();
return rc;
}
memset(&myproto_protosw, 0 ,sizeof(myproto_protosw));
myproto_protosw.type = SOCK_RAW;
myproto_protosw.protocol = IPPROTO_MYPROTO;
myproto_protosw.prot = &myproto_prot;
extern const struct proto_ops inet_dgram_ops; // defined in ipv4/af_inet.c
myproto_protosw.ops = &inet_dgram_ops;
myproto_protosw.flags = INET_PROTOSW_REUSE;
inet_register_protosw(&myproto_protosw);
return 0;
}
void cleanup_module(void)
{
int rc = 0;
rc = inet_del_protocol(&myproto_protocol, IPPROTO_MYPROTO);
if(rc == 0)
printk(KERN_INFO "Protocol removed successful\n");
else
printk(KERN_INFO "Protocol removal failed\n");
proto_unregister(&myproto_prot);
printk(KERN_INFO "Module cleaned up\n");
return;
}

Thread issue in socket Programming

I have the following codes..
server.c
#include <stdio.h>
#include "./../linux.h"
#include "./tcp.h"
#include <pthread.h>
static int clients = 0;
static int* memptr = NULL;
void serve(void*);
int* push(int* memptr, int nsfd) {
clients++;
if (clients == 1)
memptr = (int*)malloc(sizeof(int) * clients);
else
memptr = (int*)realloc(memptr, sizeof(int) * clients);
memptr[clients - 1] = nsfd;
return memptr;
}
int main(int argc, char** argv) {
pthread_t thread[2];
int threadCount = 0;
if (argc != 3){
printf("\nUsage: ./server port_number maximum_clients\n");
return 1;
}
static struct sockaddr_in sock, sock_client;
int len, new_sock_fd;
int sock_fd = socket(PF_INET, SOCK_STREAM, 0);
if (sock_fd == -1){
perror("socket");
exit(1);
}
sock.sin_family = PF_INET;
sock.sin_port = htons(atoi(argv[1]));
sock.sin_addr.s_addr = inet_addr("0.0.0.0");
len = sizeof(sock);
if ( bind(sock_fd, (struct sockaddr *)&sock, len) == -1){
perror("bind");
exit(1);
}
if ( listen(sock_fd, atoi(argv[2])) == -1){
perror("listen");
exit(1);
}
while(1) {
new_sock_fd = accept(sock_fd, (struct sockaddr *)&sock_client, (socklen_t *)&len);
memptr = push(memptr, new_sock_fd);
if (new_sock_fd == -1){
perror("accept");
exit(1);
}
pthread_create(&(thread[threadCount]), NULL, (void*)&serve, (void *)&new_sock_fd);
pthread_join(thread[threadCount++], NULL);
printf("threadCount = %d\n", threadCount);
sleep(1);
}
return 0;
}
void serve(void* fd){
int* new_sock_fd = (int*)fd;
Packet packet;
while(1){
bzero(&packet, sizeof(packet));
read(*new_sock_fd , &packet, sizeof(packet));
printf("%d\n", *new_sock_fd);
//printf("recipientId = %d\n", packet.recipientId);
// printf("message = %s\n", packet.data);
write(memptr[packet.recipientId - 1], packet.data, 1024);
}
pthread_exit(0);
}
and the tcp.h looks like
#ifndef __TCP_H__
# define __TCP_H__
typedef struct {
int recipientId; // this is the reciever ID
char data[1024]; // this is the main data part
}Packet;
#endif /* __TCP_H__ */
and each client.h looks like this
#include <stdio.h>
#include "./../linux.h"
#include "./tcp.h"
#include <pthread.h>
void print(void);
void scan(void);
int sock_fd;
int main(int argc, char** argv) {
if (argc != 3){
printf("\nUsage: ./client port_number server_ip\n");
return 1;
}
static struct sockaddr_in sock;
int len;
pthread_t thread1, thread2;
sock_fd = socket(PF_INET, SOCK_STREAM, 0);
if (sock_fd == -1){
perror("socket");
exit(1);
}
sock.sin_family = PF_INET;
sock.sin_port = htons(atoi(argv[1]));
sock.sin_addr.s_addr = inet_addr(argv[2]);
len = sizeof(sock);
if ( connect(sock_fd, (struct sockaddr *)&sock , len) == -1 ){
perror("connect");
exit(1);
}
pthread_create(&thread1, NULL, (void*)&print, NULL);
pthread_create(&thread2, NULL, (void*)&scan, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
void print(){
char messege[1024];
while(1){
if (read(sock_fd, messege, 1024) == -1){
perror("read");
return;
}
printf("messege = %s\n", messege);
}
pthread_exit(0);
}
void scan(void){
Packet packet;
while(1){
printf("Enter the reciver ID: ");
scanf("%d", &packet.recipientId);
printf("Enter the data: ");
scanf("%s", packet.data);
if ( write(sock_fd, &packet, sizeof(packet)) == -1) {
perror("read");
return;
}
}
pthread_exit(0);
}
Now the problems are
when I am running the server & the in 2 terminals, 2 clients after each client is accepted threadCount should be printed at the server end but it is not printing. It means the execution stops/skips after the first pthread_join but WHY ??
After connecting two threads, when I sent the data from 1st client to the 1st client itself, it works but not from the 1st client to the 2nd client..rather it is sending to the server terminal window. WHY ??
When sent from the second client nothing works ( sending itself or client 1)..WHY??
Please help..And thanks for patiently reading all the codes above.
TCP is a byte stream protocol, not a message protocol. You are calling TCP functions and expecting them to send or receive messages. They don't. If you want to send or receive messages, you have to implement a message protocol, write functions that send and receive messages, and then call those functions.
if (read(sock_fd, messege, 1024) == -1){
perror("read");
return;
}
printf("messege = %s\n", messege);
This call to printf is a disaster. The %s format specifier is for C-style strings, not arbitrary chunks of bytes received from a byte stream. For the most obvious way to see how bad this is, consider this --- how should printf decide how many bytes to print? You threw away the value read returned after you compared it to -1, so you have no idea how many bytes you received.
I'm sure there are other issues with your code, but the fact that the fundamental design is broken makes it not worth fixing those issues. Instead, design a message protocol and implement that.

posix multithread.With Multiple threas using one socket to receive data , when will the data be taken away from recv buffer?

I use multuple thread to receive data from one socket. they all can receive the same data. I want to know when the data will be taken away from recv buffer? Why does not one thread receive the next data when former thread read former data.
pthread_create(&(ntid[i]), NULL, find_host, (void *)&start_addr);
int find_host(void * arg)
{
int sockfd;
unsigned long ip ;
tv.tv_sec = 0;
tv.tv_usec = 100000;
struct sockaddr_in from;
char sendpacket[PACKET_SIZE];
char recvpacket[PACKET_SIZE];
ip = *(unsigned long *)arg;
struct sockaddr_in present_addr;
if( (sockfd=socket(AF_INET,SOCK_RAW,protocol->p_proto) )<0)
{
perror("socket error");
exit(1);
}
setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size) );
if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))<0){
printf("socket option SO_RCVTIMEO not support\n");
return;
}
bzero(&present_addr,sizeof(present_addr));
present_addr.sin_family=AF_INET;
present_addr.sin_addr.s_addr = htonl(ip);
pthread_mutex_unlock(&lock);
printf("PING (%s): %d bytes data in ICMP packets.\n",
inet_ntoa(present_addr.sin_addr),ICMP_DATA_LEN);
send_packet(sockfd, sendpacket, present_addr);
recv_packet(sockfd, recvpacket, from);
close(sockfd);
}
void recv_packet(int sockfd, char * recvpacket, struct sockaddr_in from)
{ int n,from_len;
extern int errno;
int nreceived = 0;
struct timeval recv_time;
from_len = sizeof(from);
while (nreceived < MAX_SEND_TIMES)
{
if((n=recvfrom(sockfd,recvpacket, PACKET_SIZE, 0,
(struct sockaddr *)&from,&from_len)) <0)
{
if(errno == EWOULDBLOCK || errno== EAGAIN )
{
printf("recvfrom Timeout!!!!\n");
pthread_exit(NULL);
}
}
gettimeofday(&recv_time,NULL);
if (1 == unpack(recv_time, recvpacket, n, from))
{
printf(" find %u\n", (unsigned short)pthread_self());
nreceived++;
}
else
printf(" not find\n");
}
}

accept/epoll problem

I have this code that uses epoll and it has a problem. When I run it, it gives output:
Server-socket() is OK...
Server-bind() is OK...
3
4
accept: Invalid argument
I'm running it on ubuntu linux, system updated, both as limited user and root
what is wrong with the input to accept? What should I change?
struct epoll_event ev, events[MAX_EVENTS];
struct sockaddr_in serveraddr;
int listen_sock, conn_sock, nfds, epollfd;
int yes = 1;
/* Set up listening socket, 'listen_sock' (socket(),
bind(), listen()) */
if((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Server-socket() error lol!");
//just exit lol!
exit(1);
}
printf("Server-socket() is OK...\n");
//"address already in use" error message
/*if(setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("Server-setsockopt() error lol!");
exit(1);
}
printf("Server-setsockopt() is OK...\n");*/
// bind
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(PORT);
memset(&(serveraddr.sin_zero), '\0', 8);
if(bind(listen_sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
{
perror("Server-bind() error lol!");
exit(1);
}
printf("Server-bind() is OK...\n");
epollfd = epoll_create(MAX_EVENTS);
if (epollfd == -1) {
perror("epoll_create");
exit(EXIT_FAILURE);
}
ev.events = EPOLLIN;
ev.data.fd = listen_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
perror("epoll_ctl: listen_sock");
exit(EXIT_FAILURE);
}
for (;;) {
nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_pwait");
exit(EXIT_FAILURE);
}
for (int n = 0; n < nfds; ++n) {
if (events[n].data.fd == listen_sock) {
struct sockaddr_in clientaddr;
socklen_t addrlen = sizeof(clientaddr);
cout <<listen_sock <<'\n' <<epollfd <<'\n';
conn_sock = accept(listen_sock, (struct sockaddr *) &clientaddr, &addrlen);
if (conn_sock == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
fcntl(conn_sock, F_SETFL, fcntl(conn_sock, F_GETFD, 0)|O_NONBLOCK);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = conn_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
&ev) == -1) {
perror("epoll_ctl: conn_sock");
exit(EXIT_FAILURE);
}
} else {
printf("%d\n", events[n].data.fd);
}
}
}
You forgot to call listen() after bind():
listen(listen_sock, 5);
I built your source and had the same results. The epoll_wait returns immediately even though there is nothing to accept.
It appears to be the case that using epoll_wait instead of listen is not supported behavior.

Resources