Why recv() from socket does not block - linux

I create a TCP server socket that listens to connect() requests and accept() them. After accepting a client socket receives data from it. I want recv() function to block with a timeout, but it seems to be non-blocking.
I have achieved the client to be in blocking mode when receiving response from the server, but it does not seem to work the same with the server side.
Below I copy-paste the server side that I want to receive data in blocking mode:
int clientSocket = accept(_serverSocket, (struct sockaddr *)NULL, NULL);
if (clientSocket < 0)
return -1;
// set TIMEOUT option to server socket
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 500 * 1000;
int sockOptRet = setsockopt(clientSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
struct linger sl;
sl.l_onoff = 1; /* non-zero value enables linger option in kernel */
sl.l_linger = 0; /* timeout interval in seconds */
setsockopt(clientSocket, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl));
char _rcvBuffer[sizeof(can_frame)];
int numBytesRcv = recv(clientSocket, _rcvBuffer, sizeof(can_frame), 0);
I have also tried it with MSG_WAITALL flag but it does not change anything...

Your code should clearly block, but your timeout of 0.5s doesn't do showing it justice.
If you increase the timeout to something more conspicuous such as 2s and graft the code onto, e.g., beej's tpc server template, you get something like:
/*
** server.c -- a stream socket server demo
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#define PORT "3490" // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold
void sigchld_handler(int s)
{
// waitpid() might overwrite errno, so we save and restore it:
int saved_errno = errno;
while(waitpid(-1, NULL, WNOHANG) > 0);
errno = saved_errno;
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
freeaddrinfo(servinfo); // all done with this structure
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("server: waiting for connections...\n");
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
// set TIMEOUT option to server socket
struct timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0 * 500 * 1000;
int sockOptRet = setsockopt(new_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
struct linger sl;
sl.l_onoff = 1; /* non-zero value enables linger option in kernel */
sl.l_linger = 0; /* timeout interval in seconds */
setsockopt(new_fd, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl));
char can_frame[1024];
char _rcvBuffer[sizeof(can_frame)];
int numBytesRcv = recv(new_fd, _rcvBuffer, sizeof(can_frame), 0);
if (send(new_fd, "Hello, world!", 13, 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
return 0;
}
Now if your run this and then do:
nc localhost 3490
without typing a line to send, there should be a distinct 2-second wait
before the server gives up on you, indicating that the recv is indeed blocking.

Related

How to use socat proxy to intercept Unix domain socket sending ancillary data?

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.

Linux Socket Programming : listen() call showing unexpected behaviour

I was writing a simple socket program for a server, where I got a hang in listen() call. Surprisingly, this piece of code hangs :
if((res = listen(sockfd, 5)) == -1)
{
perror("Error in listening over socket");
exit(1);
}
How come this is possible? Here's my full code for reference :
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define MYPORT 7891
int main()
{
int sockfd, newfd, res;
struct sockaddr_in my_addr, their_addr;
socklen_t their_addr_size;
char msg[100] = {'\0'};
/* open a socket for the server */
if((sockfd = socket(AF_INET, SOCK_STREAM,0)) == -1)
{
perror("Error opening socket");
exit(1);
}
printf("Socket opened successfully\n");
/* specify the interface details, where the server should listen for incoming messages. It is set by bind */
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MYPORT);
my_addr.sin_addr.s_addr = INADDR_ANY; /* listen on every interface, eth0, wlan, whatever f**kin place */
memset(&(my_addr.sin_zero),0,8);
if((res = bind(sockfd, (struct sockaddr *)&(my_addr), sizeof(struct sockaddr_in))) == -1)
{
perror("Error while bind()");
exit(1);
}
printf("Bind() is successfull\n");
/* listen on the socket, setting the waiting queue size to max 5 connections. Other connections will get ECONNREFUSED error */
if((res = listen(sockfd, 5)) == -1)
{
perror("Error in listening over socket");
exit(1);
}
// if(listen(sockfd,5)==0)
// printf("Listening\n");
// else
// printf("Error\n");
printf("Listening....");
/* accept incoming request */
their_addr_size = sizeof(struct sockaddr_in);
if((newfd = accept(sockfd, (struct sockaddr *)&their_addr, &their_addr_size)) == -1)
{
perror("Error accepting connection");
exit(1);
}
/* write data */
printf("Enter the data to be sent\n");
while(1)
{
scanf("%s",msg);
write(newfd, msg, strlen(msg));
}
/* though it never comes here due to infinite while loop */
close(newfd);
close(sockfd);
return 0;
}
I am not getting "Listening...".
It was due to the sdtout data buffered. Doing fflush(stdout), gave the proper print. And the process is now blocked at expected position accept().

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.

UDP broadcasting on same machine?

I wrote a broadcaster and a listener which recvfrom a particular port on the system. I used REUSEADDR option for the socket in listener, to make multiple instances of listener monitor the same port on same system.
When I run the listener on different machines, and send packet from another machine, all the listeners receives the packet. but when I run multiple instances of listener on same machine and if I try sending udp packets, only the first instance of listener gets the packet not all. I want to broadcast UDP packets on same machine and want all the listeners to receive the packet. I am on linux.
I followed the Beej's Guide.
Edit 01
listener code
/*
** listener.c -- a datagram sockets "server" demo
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define MYPORT "4950" // the port users will be connecting to
#define MAXBUFLEN 100
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int argc, char *argv[])
{
int sockfd;
struct addrinfo hints, *servinfo, *p;
int rv;
int numbytes;
struct sockaddr_storage their_addr;
char buf[MAXBUFLEN];
socklen_t addr_len;
char s[INET6_ADDRSTRLEN];
int reuse_addr = 1;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("listener: socket");
continue;
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
if(errno == EADDRINUSE)
{
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
&reuse_addr, sizeof reuse_addr) < 0)
perror("setsockopt(): REUSEADDR\n"),exit(1);
}
else
{
close(sockfd);
perror("listener: bind");
continue;
}
}
break;
}
if (p == NULL) {
fprintf(stderr, "listener: failed to bind socket\n");
return 2;
}
freeaddrinfo(servinfo);
printf("listener: waiting to recvfrom...\n");
addr_len = sizeof their_addr;
if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0,
(struct sockaddr *)&their_addr, &addr_len)) == -1) {
perror("recvfrom");
exit(1);
}
printf("listener: got packet from %s\n",
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s));
printf("listener: packet is %d bytes long\n", numbytes);
buf[numbytes] = '\0';
printf("listener: packet contains \"%s\"\n", buf);
close(sockfd);
return 0;
}
Set socket option to SO_REUSEPORT in linstener.
SO_REUSEPORT - socket option allows multiple sockets on the same host to bind to the same port
Make accept_local as 1 using echo in SYSFS.
/proc/sys/net/ipv4/conf/all # cat accept_local
1
This will allow local communication.

Given a port number, how to use netstat to find the connection detail?

I have a socket server code as below:
/*
** server.c -- a stream socket server demo
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#define PORT "3490" // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold
void sigchld_handler(int s)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
return 2;
}
freeaddrinfo(servinfo); // all done with this structure
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("server: waiting for connections...\n");
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
if (send(new_fd, "Hello, world!", 13, 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
return 0;
}
It uses port 3490. When I run it on my Mac OS X, I try to use the netstat command to find this connection according to the port number:
netstat -anpt | grep 3490
the output is empty. What's the reason for it?
Linux and OS X's implementations of netstat are quite a bit different from each other, so you can't just take a netstat command that works on linux and expect it to work (let alone do the same thing) on OS X. In particular, OS X's netstat doesn't have a -t option, and it has -p, but it means something completely different from linux's (actually, on OS X, -p shows stats for the specified protocol, and since "t" isn't a recognized protocol, you should get an error from this command).
I presume the actual goal here is to find out about the process listening on port 3490? If so, OS X's netstat command can't do this; it has no capability to display information about the process attached to the port. For that, you need lsof: lsof -itcp:3490. Note that lsof cannot check processes you don't own; if the socket server is not running under your UID, you need to sudo the lsof command in order to see it.

Resources