#include <netinet/in.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <assert.h>
static int create_local_sock(void)
{
struct sockaddr_in un;
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&un, 0, sizeof(un));
un.sin_family = AF_INET;
un.sin_port = htons(8888);
un.sin_addr.s_addr = 0;
if(bind(sockfd, (struct sockaddr *)&un, sizeof(un))<0){
assert(0);
}
listen(sockfd, 10);
return sockfd;
}
ssize_t prev_recv, curr_recv;
void *print_fun(void *arg)
{
while(1){
sleep(1);
ssize_t curr_recv1 = curr_recv;
printf("Recv %d MB/s\n", (curr_recv1 - prev_recv)/1024/1024);
prev_recv = curr_recv1;
}
}
int s_main(int argc, char **argv)
{
char buf[2048];
int fd = create_local_sock();
pthread_t thr;
pthread_create(&thr, NULL, print_fun, NULL);
while(1){
int client = accept(fd, NULL, NULL);
while(1){
ssize_t len = recv(client, buf, sizeof(buf), 0);
if(len > 0){
curr_recv += len;
}else{
break;
}
}
}
}
ssize_t prev_send, curr_send;
void *print_fun_c(void *arg)
{
while(1){
sleep(1);
ssize_t curr_send1 = curr_send;
printf("Send %d MB/s\n", (curr_send1 - prev_send)/1024/1024);
prev_send = curr_send1;
}
}
int c_main(int argc, char **argv)
{
char buf[2048];
struct sockaddr_in un;
int fd = socket(AF_INET, SOCK_STREAM, 0);
memset(&un, 0, sizeof(un));
un.sin_family = AF_INET;
un.sin_port = htons(8888);
un.sin_addr.s_addr = inet_addr(argv[1]);
connect(fd, (struct sockaddr*)&un, sizeof(un));
pthread_t thr;
pthread_create(&thr, NULL, print_fun_c, NULL);
while(1){
ssize_t len = send(fd, buf, 1400, 0);
if(len > 0){
curr_send += len;
}else{
break;
}
}
}
int main(int argc, char **argv){
if(strcmp(argv[1], "s")==0) return s_main(argc,argv);
return c_main(argc,argv);
}
I have a simple tcp receiving server and client, they both receive/send packets in a loop as quick as possible. I use the payload 1400 seems the mtu is 1500. In real testing, the throughput is only 1/3 comparing with iperf3.
I cannot understand why it has so much difference.
I have checked the cpu usage. Very similar. What hurts my performance?
Related
I have two programs, a server and a client. The server opens a file, writes data to it, and then send its file descriptor to the client over a unix domain socket. Everything works fine untill I introduce a socat proxy in between.
socat -x -v UNIX-LISTEN:/tmp/unixSockSendFe,mode=775,reuseaddr,fork UNIX-CONNECT:/tmp/unixSockSendFd
Explanation
The server listens on /tmp/unixSockSendFd, socat connects to it(UNIX-CONNECT:/tmp/unixSockSendFd), and creates another Unix domain socket(UNIX-LISTEN:/tmp/unixSockSendFe,mode=775,reuseaddr,fork), on which the client connects. Any communication between the client and server gets relayed through socat, which prints the bytes sent in their binary (-x option), and ascii (-v option) form.
If I don't use socat, and client directly connects to server(on /tmp/unixSockSendFd socket), everything works fine, but when socat is used as a proxy, the client crashes with a segmentation fault.
Server
/*Server code - sendfd.c*/
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
char *socket_path = "/tmp/unixSockSendFd";
char *file="/tmp/abcd.txt" ;/*file whose fd is to be sent*/
int sendfd(int sock, int fd);
int recvfd(int s);
char data[]="sahil\0";
int main(int argc, char *argv[]) {
struct sockaddr_un addr;
char buf[100];
buf[0]='\n';
int fd,rc,confd;
int fd_to_send;
int temp,len;
temp=1;
fd_to_send=open(file,O_TRUNC|O_RDWR|O_CREAT,S_IRWXU|S_IRWXG|S_IRWXO);
if(fd_to_send==-1)
{
perror("file open error");
return -1;
}
if (argc > 1) socket_path=argv[1];
if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket error");
exit(-1);
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
if (*socket_path == '\0') {
*addr.sun_path = '\0';
strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2);
} else {
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
}
unlink(socket_path);
if(bind(fd,(struct sockaddr*)&addr,sizeof(addr))==-1){
perror("bind error");
return -1;
}
/*Writing data to file before sending fd*/
len=write(fd_to_send,data,(int)strlen(data));
fsync(fd_to_send);
printf("(len=%d)data written in file(content between ## marks) ##%s##\n",len,data);
listen(fd,1);
for(;;){
confd=accept(fd,NULL,NULL);
if(confd==-1)
{
perror("accept error");
continue;
}
else{
printf("new client connected ... sending fd ... \n");
sendfd(confd,fd_to_send);
close(confd);
}
}
return 0;
}
int sendfd(int sock, int fd)
{
struct msghdr hdr;
struct iovec data;
char cmsgbuf[CMSG_SPACE(sizeof(int))];
char dummy = '*';
data.iov_base = &dummy;
data.iov_len = sizeof(dummy);
memset(&hdr, 0, sizeof(hdr));
hdr.msg_name = NULL;
hdr.msg_namelen = 0;
hdr.msg_iov = &data;
hdr.msg_iovlen = 1;
hdr.msg_flags = 0;
hdr.msg_control = cmsgbuf;
hdr.msg_controllen = CMSG_LEN(sizeof(int));
struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*(int*)CMSG_DATA(cmsg) = fd;
//memcpy((CMSG_DATA(cmsg)), &fd, sizeof(fd)); -- from ivshmem server code - this too works instead of previous line
int n = sendmsg(sock, &hdr, 0);
if(n == -1)
printf("sendmsg() failed: %s (socket fd = %d)\n", strerror(errno), sock);
return n;
}
int recvfd(int s)
{
int n;
int fd;
char buf[1];
struct iovec iov;
struct msghdr msg;
struct cmsghdr *cmsg;
char cms[CMSG_SPACE(sizeof(int))];
iov.iov_base = buf;
iov.iov_len = 1;
memset(&msg, 0, sizeof msg);
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = (caddr_t)cms;
msg.msg_controllen = sizeof cms;
if((n=recvmsg(s, &msg, 0)) < 0)
return -1;
if(n == 0){
perror("unexpected EOF");
return -1;
}
cmsg = CMSG_FIRSTHDR(&msg);
memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
return fd;
}
Client
/*Client code - recvfd.c*/
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
char *socket_path = "/tmp/unixSockSendFe";
int sendfd(int sock, int fd);
int recvfd(int s);
int fd_received;
int main(int argc, char *argv[]) {
struct sockaddr_un addr;
char buf[100];
buf[0]='\n';
int fd,rc,confd;
int temp,len;
temp=1;
if (argc > 1) socket_path=argv[1];
if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket error");
exit(-1);
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
if (*socket_path == '\0') {
*addr.sun_path = '\0';
strncpy(addr.sun_path+1, socket_path+1, sizeof(addr.sun_path)-2);
} else {
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
}
if(connect(fd,(struct sockaddr*)&addr,sizeof(addr))==-1)
{
perror("connect error");
exit(-1);
}
fd_received=recvfd(fd);
lseek(fd_received,0,SEEK_SET);
len=read(fd_received,buf,5);
if(len<0)
{
perror("read error");
}
printf("(fd_received=%d,len=%d) first %d characters read from the file whoes fd was received(content within ##) ##%.*s##\n",fd_received,len,5,5,buf);
return 0;
}
int sendfd(int sock, int fd)
{
struct msghdr hdr;
struct iovec data;
char cmsgbuf[CMSG_SPACE(sizeof(int))];
char dummy = '*';
data.iov_base = &dummy;
data.iov_len = sizeof(dummy);
memset(&hdr, 0, sizeof(hdr));
hdr.msg_name = NULL;
hdr.msg_namelen = 0;
hdr.msg_iov = &data;
hdr.msg_iovlen = 1;
hdr.msg_flags = 0;
hdr.msg_control = cmsgbuf;
hdr.msg_controllen = CMSG_LEN(sizeof(int));
struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*(int*)CMSG_DATA(cmsg) = fd;
int n = sendmsg(sock, &hdr, 0);
if(n == -1)
printf("sendmsg() failed: %s (socket fd = %d)\n", strerror(errno), sock);
return n;
}
int recvfd(int s)
{
int n;
int fd;
char buf[1];
struct iovec iov;
struct msghdr msg;
struct cmsghdr *cmsg;
char cms[CMSG_SPACE(sizeof(int))];
iov.iov_base = buf;
iov.iov_len = 1;
memset(&msg, 0, sizeof msg);
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = (caddr_t)cms;
msg.msg_controllen = sizeof cms;
if((n=recvmsg(s, &msg, 0)) < 0)
return -1;
if(n == 0){
perror("unexpected EOF");
return -1;
}
cmsg = CMSG_FIRSTHDR(&msg);
memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
return fd;
}
On running client (recvfd) I get segmentation fault.
./recvfd
[1] 6104 segmentation fault (core dumped) ./recvfd
Here are lines from running gdb with coredump
Core was generated by `./recvfd'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000000000400cf9 in recvfd (s=3) at recvfd.c:146
146 memmove(&fd, CMSG_DATA(cmsg), sizeof(int));
Here is the core dump - Link.
I want to sniff the communication happening between the two processes when the file descriptor is being sent. I am not able to figure out why the client crashes when run with socat, but doesn't when run without it.
Update 1
While using socat to sniff communication happening between two processes of a well established open source project (ivshmem - used for sharing memory between running virtual machines, also a part of Intel DPDK, Link), I observed the following.
None of the processes crash on using socat
When socat is used, the file descriptor is not properly sent, and does not get added to the recipient process.
When socat is not used, and the two processes are connected directly, the file descriptor gets sent properly, and gets added to the recipient process.
I create chat with clients and server. But the client can't connect to the server. Please tell me what is wrong?
Server code
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define BUFOR 512
int main(int argc, char *argv[])
{
int fd, serverLength, cLength;
struct sockaddr_in serverAddr, c_addr[2], clientAddr;
cLength = sizeof(clientAddr);
char buf[BUFOR];
int clients = 0;
int c_port[2];
if(argc != 2)
{
printf(" portu");
exit(1);
}
uint16_t port = atoi( argv[ 1 ] );
if ((fd = socket(AF_INET, SOCK_DGRAM, 0))==-1)
{
perror("Blad socket");
exit(1);
}
bzero((char*) &serverAddr, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(port);
serverLength = sizeof(serverAddr);
if (bind(fd, (struct sockaddr* ) &serverAddr, serverLength)==-1)
{
perror("Blad bind");
exit(1);
}
for(;;)
{
printf("Receiving...\n");
if (recvfrom(fd, buf, BUFOR, 0, (struct sockaddr*)&clientAddr, &cLength)==-1)
{
perror("Blad recvfrom");
exit(1);
}
if (clients==0)
{
c_addr[0] = clientAddr;
c_port[0] = ntohs(c_addr[0].sin_port);
clients++;
printf("Client 0 was connected. Port: %d\n",c_port[0]);
sendto(fd, "I am only one cleint.", 24, 0, (struct sockaddr*)&clientAddr, cLength);
}else if(clients==1)
{
if (c_port[0]==ntohs(clientAddr.sin_port))
{
sendto(fd, "I am only one client.", 24, 0, (struct sockaddr*)&c_addr[0], sizeof(c_addr[0]));
printf("One cleint\n");
}else
{
c_addr[1] = clientAddr;
c_port[1] = ntohs(c_addr[1].sin_port);
clients++;
printf("Second cleint\n");
sendto(fd, buf, BUFOR, 0, (struct sockaddr*)&c_addr[0], sizeof(c_addr[0]));
}
}else
{
if (c_port[0]==ntohs(clientAddr.sin_port))
{
printf("Sending emssage for client 1\n");
if (sendto(fd, buf, BUFOR, 0, (struct sockaddr*)&c_addr[1], sizeof(c_addr[0]))==-1)
{
clients--;
perror("Error senttoen");
}
}else
{
printf("Sending message for client 0\n");
if (sendto(fd, buf, BUFOR, 0, (struct sockaddr*)&c_addr[0], sizeof(c_addr[1]))==-1)
{
clients--;
perror("Blad senttoen");
}
}
}
}
close(fd);
return 0;
}
Client code
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <signal.h>
#define BUFLEN 512
int main(int argc, char *argv[])
{
struct sockaddr_in serv_addr;
int sockfd;
socklen_t slen;
slen=sizeof(serv_addr);
char buf[BUFLEN];
if(argc != 3)
{
printf("Usage : %s <Server-IP>\n",argv[2]);
exit(0);
}
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
{
perror("Socket Error");
exit(1);
}
uint16_t port = atoi( argv[ 1 ] );
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
serv_addr.sin_addr.s_addr = inet_addr(argv[2]);
while(1)
{
bzero(buf,BUFLEN);
printf("Attempting to READ to socket %d: ",sockfd);
fflush(stdout);
if(recvfrom(sockfd, buf, BUFLEN, 0, (struct sockaddr*)&serv_addr, &slen)==-1)
{
perror("Blad bind");
exit(1);
}
printf("The message from the server is: %s \n",buf);
printf("Please enter the message to send: ");
bzero(buf,BUFLEN);
fgets(buf,BUFLEN,stdin);
printf("Attempting to write to socket %d: ",sockfd);
fflush(stdout);
if (sendto(sockfd, buf, BUFLEN, 0, (struct sockaddr*)&serv_addr, slen)==-1)
{
perror("Blad bind");
exit(1);
}
}
close(sockfd);
return 0;
}
It seems the sendto is blocked by recvfrom, but I don't know how to create it in infinitable loop.
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.
Why? I didn't do anything on the other peer!
I was using massive threads to get data from the server. When the thread count is small, it's ok. But when the thread count is very large, recv() return -1 and errno indicates "Connection reset by peer".
Here is an example to reproduce the issue:
server.cc
#include <arpa/inet.h>
#include <assert.h>
#include <netinet/in.h>
#include <pthread.h>
#include <unistd.h>
char buffer[4096];
inline int send_all(int socket_fd, const char* data, size_t size, int flags)
{
int result;
const char* pos = data;
while (size > 0)
{
result = send(socket_fd, pos, size, flags);
assert(result > 0);
pos += result;
size -= result;
}
return 0;
}
inline int recv_all(int socket_fd, void* data, size_t size, int flags)
{
int result = recv(socket_fd, data, size, flags | MSG_WAITALL);
assert(((size_t) result) == size);
return 0;
}
void* server_thread(void* arg)
{
int socket_fd = (int) ((long) arg);
// recv some info first
recv_all(socket_fd, buffer, 1, 0);
// simulate some computation
for (int i = 0; i < 0xffff; i ++)
for (int j = 0; j < 0xffff; j ++);
// send data
for (int i = 0; i < 4096; i ++)
send_all(socket_fd, buffer, sizeof(buffer), 0);
// the peer is closed, return 0
recv(socket_fd, buffer, 1, MSG_WAITALL);
close(socket_fd);
pthread_detach(pthread_self());
return NULL;
}
int main(void)
{
int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
assert(listen_socket != -1);
struct sockaddr_in listen_address;
listen_address.sin_family = AF_INET;
listen_address.sin_port = htons(11282);
listen_address.sin_addr.s_addr = INADDR_ANY;
int result = bind(listen_socket,
(struct sockaddr*) &listen_address,
sizeof(listen_address));
assert(result != -1);
result = listen(listen_socket, 5);
assert(result != -1);
while (true)
{
int server_socket = accept(listen_socket, NULL, NULL);
assert(server_socket != -1);
pthread_t tid;
result = pthread_create(&tid,
NULL,
server_thread,
(void *) ((long) server_socket));
assert(result != -1);
}
return 0;
}
client.cc
#include <arpa/inet.h>
#include <assert.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
pthread_t threads[4096];
char buffer[4096];
inline int send_all(int socket_fd, const char* data, size_t size, int flags)
{
int result;
const char* pos = data;
while (size > 0)
{
result = send(socket_fd, pos, size, flags);
assert(result > 0);
pos += result;
size -= result;
}
return 0;
}
inline int recv_all(int socket_fd, void* data, size_t size, int flags)
{
int result = recv(socket_fd, data, size, flags | MSG_WAITALL);
assert(((size_t) result) == size);
return 0;
}
void* client_thread(void* arg)
{
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
assert(socket_fd != -1);
struct sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(11282);
server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
int result = connect(socket_fd,
(struct sockaddr *) &server_address,
sizeof(server_address));
assert(result != -1);
// send some info first
send_all(socket_fd, buffer, 1, 0);
// recv the reply data
for (int i = 0; i < 4096; i ++)
recv_all(socket_fd, buffer, sizeof(buffer), 0);
close(socket_fd);
return NULL;
}
int main(int argc, char* argv[])
{
assert(argc == 2);
// get client thread count
int thread_count = atoi(argv[1]);
assert(thread_count <= 4096);
for (int i = 0; i < thread_count; i ++)
{
int result = pthread_create(&threads[i], NULL, client_thread, NULL);
assert(result != -1);
}
for (int i = 0; i < thread_count; i ++)
pthread_join(threads[i], NULL);
return 0;
}
Usage:
./server
./client [thread_count]
I was using 480 as the thread_count, sometime I could reproduce the issue.
Hi am trying to implement net link user code and kernel code every thing works fine for unicast (src_addr.nl_groups = 0;). For mulicast, user code bind call always fails for non zero src_addr.nl_groups value. Really am not sure what value to put for multicast and how to proceed further. I checked the usage of netlink_broadcast in kernel source tree, so I put the same group Id value (RTMGRP_LINK) here. For unicast I found good number of help in internet but for multicast I don't think so . So Please help me to proceed further.
Error am getting is:
bind: No such file or directory
./a.out: can't bind socket (3)and err : -1: No such file or directory
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdio.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#define NETLINK_TEST 28
#define GROUP_IB 1
#define MAX_PAYLOAD 1024
struct sockaddr_nl src_addr, dst_addr;
struct nlmsghdr *nlh = NULL;
struct msghdr msg;
struct iovec iov;
int sock_fd;
int main(int argc, char ** argv)
{
int err;
sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
if (sock_fd<0) {
char s[BUFSIZ];
sprintf( s, "%s: can't assign fd for socket", argv[0] );
perror(s);
return -1;
}
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid();
src_addr.nl_groups = 0; // Unicast
//src_addr.nl_groups = RTMGRP_LINK; /* Multicast, bind call always fails for non zero values */
err = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
perror("bind");
if (err<0) {
char s[BUFSIZ];
sprintf( s, "%s: can't bind socket (%d)and err : %d", argv[0], sock_fd,err );
perror(s);
return -1;
}
memset(&dst_addr, 0, sizeof(dst_addr));
nlh = (struct nlhmsghdr *) malloc(NLMSG_SPACE(MAX_PAYLOAD));
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
iov.iov_base = (void *)nlh;
iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);
msg.msg_name = (void *)&dst_addr;
msg.msg_namelen = sizeof(dst_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
printf("pid : %d\n Waiting for messages from kernel...\n",getpid());
recvmsg(sock_fd, &msg, 0);
printf("Message : %s\n", NLMSG_DATA(nlh));
close(sock_fd);
return 0;
}
Netlink socket binds are sensitive to what USER you are- I've seen them reliably fail if you are not running the program in question as 'root', at least on RedHat 6.
Try running as root 1st, before changing your logic. If you get the same failure as you do in normal operation, then you know it isn't (necessarily) a permissions issue.
The issue is
sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
Does you kernel module define the NETLINK_TEST family? your own family might must be supported at kernel module and it should post the message in the proper group using nlmsg_multicast()
RTMGRP_LINK is group defined in NETLINK_ROUTE.
This sample code is example for multicast
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>
#define MYPROTO NETLINK_USERSOCK
#define MYMGRP 21
int open_netlink(void)
{
int sock;
struct sockaddr_nl addr;
int group = MYMGRP;
sock = socket(AF_NETLINK, SOCK_RAW, MYPROTO);
if (sock < 0) {
printf("sock < 0.\n");
return sock;
}
memset((void *) &addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
/* addr.nl_groups = MYMGRP; */
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
printf("bind < 0.\n");
return -1;
}
if (setsockopt(sock, 270, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)) < 0) {
printf("setsockopt < 0\n");
return -1;
}
return sock;
}
void read_event(int sock)
{
struct sockaddr_nl nladdr;
struct msghdr msg;
struct iovec iov;
char buffer[65536];
int ret;
iov.iov_base = (void *) buffer;
iov.iov_len = sizeof(buffer);
msg.msg_name = (void *) &(nladdr);
msg.msg_namelen = sizeof(nladdr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
printf("Ok, listening.\n");
ret = recvmsg(sock, &msg, 0);
if (ret < 0)
printf("ret < 0.\n");
else
printf("Received message payload: %s\n", NLMSG_DATA((struct nlmsghdr *) &buffer));
}
int main(int argc, char *argv[])
{
int nls;
nls = open_netlink();
if (nls < 0)
return nls;
while (1)
read_event(nls);
return 0;
}
kernel module:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netlink.h>
#include <net/netlink.h>
#include <net/net_namespace.h>
#define MYPROTO NETLINK_USERSOCK
#define MYGRP 21
static struct sock *nl_sk = NULL;
static void send_to_user(void)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
char *msg = "Hello from kernel";
int msg_size = strlen(msg) + 1;
int res;
pr_info("Creating skb.\n");
skb = nlmsg_new(NLMSG_ALIGN(msg_size + 1), GFP_KERNEL);
if (!skb) {
pr_err("Allocation failure.\n");
return;
}
nlh = nlmsg_put(skb, 0, 1, NLMSG_DONE, msg_size + 1, 0);
strcpy(nlmsg_data(nlh), msg);
pr_info("Sending skb.\n");
res = nlmsg_multicast(nl_sk, skb, 0, MYGRP, GFP_KERNEL);
if (res < 0)
pr_info("nlmsg_multicast() error: %d\n", res);
else
pr_info("Success.\n");
}
static int __init hello_init(void)
{
pr_info("Inserting hello module.\n");
nl_sk = netlink_kernel_create(&init_net, MYPROTO, NULL);
if (!nl_sk) {
pr_err("Error creating socket.\n");
return -10;
}
send_to_user();
netlink_kernel_release(nl_sk);
return 0;
}
static void __exit hello_exit(void)
{
pr_info("Exiting hello module.\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");