Bind a socket to a specific interface with UDP? - C - c

I'd like to know how I can bind a socket to a specific interface in C.
My #IP is X.Y.Z.3, the gateway is X.Y.Z.1 on eth1
But if I send my packet, it'll be send on the loopback interface.
The strange thing is, if I make my packet with X.Y.Z.9 (for example) as the IP SOURCE (instead of mine), it works.
Any clue?
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/time.h>
#define PCK_MAX_LEN 1024
#define IP_NAMESERV "172.20.10.1"
#define IP_ATTACKER "172.20.10.3"
#define PORT_QUERY 5555
pthread_cond_t ans_listen = PTHREAD_COND_INITIALIZER;
pthread_cond_t ans_receiv = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *fctThreadSendQuery (void *arg); // Send 1 query to random.example.com
void *fctThreadListenResponse (void *arg); // Listen for response to that query
int main (void)
{
pthread_t threadSendQuery;
pthread_t threadListenResponse;
pthread_create (&threadSendQuery, NULL, fctThreadSendQuery, NULL);
pthread_create (&threadListenResponse, NULL, fctThreadListenResponse, NULL);
pthread_join (threadListenResponse, NULL);
pthread_join (threadSendQuery, NULL);
return 0;
}
void *fctThreadSendQuery(void *arg) {
unsigned int nQuery = 1;
struct sockaddr_in *sin_attacker, *sin_resolver;
sin_attacker = calloc(1, sizeof(struct sockaddr_in));
sin_resolver = calloc(1, sizeof(struct sockaddr_in));
sin_attacker->sin_family = AF_INET;
sin_attacker->sin_addr.s_addr = inet_addr(IP_ATTACKER);
sin_attacker->sin_port = htons(PORT_QUERY);
int fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
bind(fd, sin_attacker, sizeof(struct sockaddr_in));
sin_resolver->sin_family = AF_INET;
sin_resolver->sin_addr.s_addr = inet_addr(IP_RESOLVER);
sin_resolver->sin_port = htons(53);
while (1) {
// Now, we can build and send the query
char *packet = calloc(PCK_MAX_LEN, sizeof(char));
int pck_len = 0;
int id = 0;
char *target = calloc(16, sizeof(char));
strcpy(target, randomTarget(nQuery-1));
build_packet(IP_SRC, IP_DST, PORT_QUERY, 53, packet, &pck_len, target, NAME_LEN, id, QUERY);
// Before sending the packet, we want to be sure that fctThreadListenResponse is listening
pthread_mutex_lock (&mutex);
puts("SEND: wait for RECV to LISTEN");
pthread_cond_wait (&ans_listen, &mutex);
puts("SEND: wait for RECV to LISTEN - OK");
pthread_mutex_unlock(&mutex);
sendto (fd, packet, pck_len, 0, sin_attacker, sizeof(struct sockaddr_in));
puts("SEND: PCK SENT");
pthread_mutex_lock (&mutex);
puts("SEND: wait for RECV to RECV");
pthread_cond_wait (&ans_receiv, &mutex);
puts("SEND: wait for RECV to RECV - OK");
pthread_mutex_unlock(&mutex);
nQuery++;
free(target);
free(packet);
}
free(sin_resolver);
free(sin_attacker);
pthread_exit(NULL);
}
void *fctThreadListenResponse (void *arg) {
usleep(100);
struct sockaddr_in *sin_attacker, *sin_resolver;
sin_attacker = calloc(1, sizeof(struct sockaddr_in));
sin_resolver = calloc(1, sizeof(struct sockaddr_in));
sin_attacker->sin_family = AF_INET;
sin_attacker->sin_addr.s_addr = inet_addr(IP_ATTACKER);
sin_attacker->sin_port = htons(PORT_QUERY);
int fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
bind(fd, sin_attacker, sizeof(struct sockaddr_in));
while (1) {
char *packet = calloc(PCK_MAX_LEN, sizeof(char));
unsigned int pck_len;
pthread_mutex_lock (&mutex);
pthread_cond_signal (&ans_listen);
puts("RECV: LISTENING");
pthread_mutex_unlock(&mutex);
pck_len = recvfrom(fd, packet, PCK_MAX_LEN, 0, NULL, sin_resolver);
puts("RECV: PCK RECEIVED");
if (pck_len > 0) {
pthread_mutex_lock (&mutex);
pthread_cond_signal (&ans_receiv);
pthread_mutex_unlock (&mutex);
}
free(packet);
}
pthread_exit(NULL);
}

I don't know what build_packet does, but the documentation for sendto lists only a few possible prototypes, of which only one has the parameter list you are using:
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
In your call you use:
sendto (fd, packet, pck_len, 0, sin_attacker, sizeof(struct sockaddr_in));
Where you have configured sin_attacker (the dest_addr parameter) using IP_ATTACKER, which seems to be your own address. Thus sendto sees a destination address that is hosted on the local system and sends the packet using the loopback adapter.

Related

UDP echo server with one thread per client

I had a simple TCP echo server with one thread per client (it works), so i tried to transform it into UDP but faced problem after running server:
"pthread_create() resource temporarily unavailable"
. Here is my server code:
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 1027
#define BACKLOG 5
#define MAXLINE 256
#define SA struct sockaddr
typedef struct serve_clientArg {
int socket;
SA *addr;
socklen_t addrlen;
} SCARGS;
void Pthread_create(pthread_t *thread, pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg)
{
int rc;
rc = pthread_create(thread, attr, start_routine, arg);
if(rc) {
errno = rc;
error("pthread_create()");
}
}
reads() and writen() are using recvfrom() and sendto() functions
void *serve_client(void* arg)
{
char s[MAXLINE];
ssize_t rc;
SCARGS *args = Malloc(sizeof (SCARGS));
args = (SCARGS*) arg;
int socket = args->socket;
SA *addr = args->addr;
socklen_t addrlen = args->addrlen;
free(arg);
pthread_detach(pthread_self());
while((rc = reads(socket, s, MAXLINE, addr, &addrlen)) > 0) {
writen(socket, s, rc, addr, addrlen);
}
Close(socket);
return NULL;
}
int main(void)
{
int socket;
struct sockaddr_in servaddr;
struct sockaddr_in cliaddr;
SCARGS *arg;
pthread_t thread;
socket = Socket(AF_INET, SOCK_DGRAM, 0);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
Bind(socket, (SA *) &servaddr, sizeof(servaddr));
for(;;) {
arg = Malloc(sizeof (SCARGS));
arg->socket = socket;
arg->addr = (SA*) &cliaddr;
arg->addrlen = sizeof (cliaddr);
Pthread_create(&thread, NULL, serve_client, (void*) arg);
}
return 0;
}
I also had a TCP client and after transformation into UDP it works. I think i have done a stupid mistake, but i cant find it... Please help me find mistakes!
for(;;) {
arg = Malloc(sizeof (SCARGS));
arg->socket = socket;
arg->addr = (SA*) &cliaddr;
arg->addrlen = sizeof (cliaddr);
Pthread_create(&thread, NULL, serve_client, (void*) arg);
}
You allocate memory and create new threads inside an endless loop with no kind of blocking (as you might have done in TCP with accept). Therefore it quickly runs out of resources:
"pthread_create() resource temporarily unavailable"
Apart from that you use the same socket in all threads. But when you have only a single socket it does not really make sense to have multiple threads handling it. I'm not sure what you were trying to achieve with this design.

C - Making UTP server/client chatroom with select()

I'm supposed to make the server broadcast the message it gets from a client to all the other clients connected.
The actual broadcast works, but I have no idea how to stop the clients from infinitely printing "[client]Received from friends:" when I CTRL+C the server,
OR
how to stop the Server from infinitely printing "[server]Message received..." when I CTRL+C any of the connected Clients. Or how to add a verification somewhere so that the Client will disconnect when trying to send the string "quit"
Maybe I'm asking for too much, but could someone please explain to me what exactly does select(..) do? I understand that it's monitoring the FDs, but I can't fully understand what's going on(step-by-step) after 1 second. Does it go through all FDs ,1 second for each then repeat? I kind of get the idea, but not entirely.
Thank you either way
SERVER
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#define PORT 3050 //The port used by Clients
extern int errno;
char * conv_addr (struct sockaddr_in address)
{
static char str[25];
char port[7];
strcpy (str, inet_ntoa (address.sin_addr)); /* client IP */
bzero (port, 7); /* PORT */
sprintf (port, ":%d", ntohs (address.sin_port));
strcat (str, port);
return (str);
}
void Msgs(int fd,int sd,fd_set fds,int nr);
int main ()
{
struct sockaddr_in server_addr; /* struct for Server */
struct sockaddr_in client_addr; /* struct for Clients */
fd_set readfds; /* ready-to-read File Descriptors */
fd_set actfds; /* active/existant File Descriptors */
struct timeval tv; /* time thing, for select() */
int ServerSocketFD, ClientSocketFD; /* Socket descriptors */
int optval=1; /* ????*/
int fd; /* FD used to pass through all FDs */
int nfds; /* max number of FDs */
(ServerSocketFD = socket (AF_INET, SOCK_STREAM, 0));
setsockopt(ServerSocketFD, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) );
bzero (&server_addr, sizeof (server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl (INADDR_ANY);
server_addr.sin_port = htons (PORT);
bind (ServerSocketFD, (struct sockaddr *) &server_addr, sizeof(struct sockaddr) );
listen (ServerSocketFD, 5); //listen to maximum 5 clients,no more
FD_ZERO (&actfds);
FD_SET (ServerSocketFD, &actfds); /* Add the only existant one for now */
tv.tv_sec = 1; /* wait 1s */
tv.tv_usec = 0;
nfds = ServerSocketFD; /* max value of currently used FDs */
printf ("[server] Waiting at port :%d...\n", PORT);
fflush (stdout);
while (1) /* serve clients CONCURRENTLY */
{
bcopy ((char *) &actfds, (char *) &readfds, sizeof (readfds)); /* copy all existing FDs in actfds vector to the read-to-read-FDs vector */
select(nfds+1, &readfds, NULL, NULL, &tv);
if (FD_ISSET (ServerSocketFD, &readfds)) /* if ServerSocket is ready to read stuff */
{
bzero (&client_addr, sizeof (client_addr));
int len = sizeof (client_addr);
ClientSocketFD = accept (ServerSocketFD, (struct sockaddr *) &client_addr, &len);
if (nfds < ClientSocketFD) /* adjust max FD, for select */
nfds = ClientSocketFD;
/* Add this accepted sockets' FD to the existing FDs */
FD_SET (ClientSocketFD, &actfds);
printf("[server] Client connected, with FD %d, from this address %s.\n",ClientSocketFD, conv_addr (client_addr));
fflush (stdout);
}
for (fd = 0; fd <= nfds; fd++) /* all FDs*/
{
if (fd != ServerSocketFD && FD_ISSET (fd, &readfds)) /* is a client ready to send/get messages? */
{
Msgs(fd,ServerSocketFD,actfds,nfds);
}
}
}
}
void Msgs(int fd,int ServerSocketFD,fd_set fds,int nrFD)
{
char buffer[100];
int bytes;
char msg[100];
bytes = read (fd, msg, sizeof (buffer));
/*
if(strstr(msg,"quit")!=0)
{
FD_CLR(fd, &fds);
close(fd);
exit(1);
}
*/
printf ("[server]Message received...%s\n", msg);
for(int i=0;i<=nrFD;i++)
{
if(i!=fd && i!=ServerSocketFD)
{
write (i, msg, bytes);
}
}
}
CLIENT
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <string.h>
#include <arpa/inet.h>
extern int errno;
int port;
int main (int argc, char *argv[])
{
int ClientSocketFD;
struct sockaddr_in server_addr;
char msg[100];
char reply[100];
if (argc != 3)
{
printf ("[client] Sintax: %s <server_address> <port>\n", argv[0]);
return -1;
}
port = atoi (argv[2]);
ClientSocketFD = socket (AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(argv[1]);
server_addr.sin_port = htons (port);
connect(ClientSocketFD, (struct sockaddr *) &server_addr,sizeof (struct sockaddr));
int pid;
if((pid=fork())==-1)
{
perror("Error fork()");
exit(10);
}
if(pid==0) //CHILD
{
while(1)
{
bzero(msg,100);
printf ("[client]Send something to other clients: ");
fflush (stdout);
read (0, msg, 100);
if(strstr(msg,"quit")!=0)
{
break;
}
write (ClientSocketFD, msg, 100);
}
exit(7);
}
else if(pid > 0) //PARENT
{
while(1)
{
bzero(reply,100);
read (ClientSocketFD, reply, 100);
printf ("[client]Received from friends: %s\n", reply);
}
}
close (ClientSocketFD);
}
I have no idea how to stop the clients from infinitely printing "[client]Received from friends:" when I CTRL+C the server
read() returns 0 if the server terminates, so replace the while(1) loop in the client PARENT by
while (bzero(reply, 100), read(ClientSocketFD, reply, 100) > 0)
printf("[client]Received from friends: %.100s\n", reply);
kill(pid, SIGTERM); // terminate also the child
(and #include <signal.h>).
how to stop the Server from infinitely printing "[server]Message received..." when I CTRL+C any of the connected Clients
read() returns 0 if the client terminates, so call
Msgs(fd, ServerSocketFD, &actfds, nfds);
change the Msgs() type to
void Msgs(int fd, int ServerSocketFD, fd_set *fds, int nrFD)
and in Msgs() after bytes = read (fd, msg, sizeof (buffer)); add
if (bytes <= 0) { FD_CLR(fd, fds); close(fd); return; }
could someone please explain to me what exactly does select(..) do? I understand that it's monitoring the FDs, but I can't fully understand what's going on(step-by-step) after 1 second. Does it go through all FDs ,1 second for each then repeat?
As wildplasser noted in his comment, select() possibly changes the timeout argument to indicate how much time was left, so after 1 second without FD activity we may well end up with a zero timeout and a useless busy loop. We need a select() timeout only if we want to do something when none of the monitored FDs gets ready within a certain time, so in your case it's better to specify no timeout at all:
select(nfds+1, &readfds, NULL, NULL, NULL);

Why do I get an unexpected port value in C?

I'm writing a program which gets an identifier from params, creates an UDP socket, gets a port, and prints <identifier>: <port>.
Then, receives some identifiers and ports from stdin and store them in memory.
In the code below, the problem is that the port variable (udp_port) get 0.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
typedef struct process {
char id[80];
int port;
int me;
} process;
int main(int argc, char* argv[]) {
if(argc<2) {
fprintf(stderr,"Use: process <ID>\n");
return 1;
}
/* NODES */
process * processes;
int num_process = 0;
/* CONECTION */
int udp_port;
int fd;
struct sockaddr_in addr, local_addr;
/* STDIN READS */
int port;
char line[80],proc[80];
/* I/O buffer mode */
setvbuf(stdout,(char*)malloc(sizeof(char)*80),_IOLBF,80);
setvbuf(stdin,(char*)malloc(sizeof(char)*80),_IOLBF,80);
/* Prepare socket */
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(0);
addr.sin_addr.s_addr = INADDR_ANY;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd == -1){
perror("SOCKET");
return 1;
}
if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) == -1){
perror("BIND");
return 1;
}
getsockname(fd, (struct sockaddr *)&local_addr, (socklen_t *) sizeof(struct sockaddr));
udp_port=ntohs(local_addr.sin_port); // Gets port
fprintf(stdout,"%s: %d\n",argv[1],udp_port); // Prints identifier: port
// Reads from stdin
for(;fgets(line,80,stdin);) {
if(!strcmp(line,"START\n"))
break;
sscanf(line,"%[^:]: %d",proc,&port);
num_process++;
processes = realloc(processes,num_process);
strcpy(processes[num_process-1].id, proc);
processes[num_process-1].port = port;
if(!strcmp(proc,argv[1])){ /* Thats me */
processes[num_process-1].me = 1;
}else{
processes[num_process-1].me = 0;
}
}
return 0;
}
But, it gets a correct value (random port) when I comment the realloc line and related lines, like this:
// Reads from stdin
for(;fgets(line,80,stdin);) {
if(!strcmp(line,"START\n"))
break;
sscanf(line,"%[^:]: %d",proc,&port);
num_process++;
//processes = realloc(processes,num_process);
//strcpy(processes[num_process-1].id, proc);
//processes[num_process-1].port = port;
if(!strcmp(proc,argv[1])){ /* Thats me */
// processes[num_process-1].me = 1;
}else{
// processes[num_process-1].me = 0;
}
}
Your code crashes if used as it is. Because you pass to realloc uninitialized pointer. Initialize processes to NULL:
process * processes = NULL;
EDIT:
Otherwise, the udp_port is non zero. And getsockname returns Bad address.
Try the following for getsockname to be successsful:
socklen_t tmp = sizeof(struct sockaddr);
getsockname (fd, (struct sockaddr *) &local_addr,&tmp);
Checking the return value of getsockname function I get a Bad address error.
The problem was that the last parameter in getsockname was incorrect:
getsockname(fd, (struct sockaddr *)&local_addr, (socklen_t *) sizeof(struct sockaddr));
sizeof returns a socklen_t instead of socklen_t *. I fixed this like this:
socklen_t size_sa = sizeof(struct sockaddr);
if(getsockname(fd, (struct sockaddr *)&local_addr, &size_sa) == -1){
perror("GETSOCKNAME");
return 1;
}

TCP Linux server lock after the first accept

I am writing a TCP client in C.
Following several tutorial I wrote my code but it can accept only the first connection to the server.
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h> //inet_addr for INADDR_ANY
#include <string.h> //for splitting (strtok)
#include <pthread.h> //thread library
#include <time.h>
#include <unistd.h> //for function close()
void* SocketHandler(void*);
int main(void) {
//socket parameters
int server_socket_desc;
int clientAddressLength = sizeof(struct sockaddr_in);
struct sockaddr_in server_addr, client_addr;
const unsigned short int PORT_NUMBER = 8963;
server_socket_desc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_socket_desc < -1) {
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server_addr.sin_family = AF_INET; //it should be always set to AF_INET
//set the server address
server_addr.sin_addr.s_addr = inet_addr("192.168.123.240");
//server_addr.sin_addr.s_addr = inet_addr("31.185.101.35");
//server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(PORT_NUMBER);
//Bind
if (bind(server_socket_desc, (struct sockaddr *) &server_addr,
sizeof(server_addr)) < 0) {
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(server_socket_desc, 10);
//Accept and incoming connection
puts("Waiting for incoming connections...");
//accept connection from an incoming client
while (1) {
int *temp_socket_desc = (int*) malloc(sizeof(int));
if ((*temp_socket_desc = accept(server_socket_desc,
(struct sockaddr *) &client_addr,
(socklen_t*) &clientAddressLength)) != -1) {
printf("----------\nConnection accepted \n");
sleep(1);
pthread_t thread_id;
int *client_socket_desc = (int*) malloc(sizeof(int));
client_socket_desc = temp_socket_desc;
pthread_create(&thread_id, NULL, &SocketHandler,
(void*) client_socket_desc);
//if thread has not terminated, pthread_detach() shall not cause it to terminate
pthread_detach(thread_id);
puts("handler assigned");
} else
puts("connection refused");
}
close(server_socket_desc);
//mysql_close(mysql_conn);
return 0;
}
/*
* This will handle connection for each client
* */
void* SocketHandler(void* lp) {
int *csock = (int*) lp;
char buffer[128];
int buffer_len = 128;
int bytecount;
memset(buffer, 0, buffer_len);
if ((bytecount = read(*csock, buffer, buffer_len) == -1)) {
fprintf(stderr, "Error receiving data\n");
close(*csock);
return 0;
}
printf("Received bytes %d\nReceived string \"%s\"\n", bytecount, buffer);
close(*csock);
free(csock);
puts("exiting thread");
//pthread_exit(0);
return 0;
}
I temporally solved the problem inserting a sleep() after the while loop but it is a very bad solution.
Can somebody explain me why the code does'n work without the sleep?
There is a problem in handling of client_socket_desc:
You allocate it only once. All threads will get the same pointer.
So later accepts will override socket descriptors value of earlier threads.
Try the following change, for allocating own memory block for each thread:
int fd = accept( server_socket_desc, (struct sockaddr *) &client_addr, (socklen_t*)
&clientAddressLength)
if ( fd != -1 )
{
pthread_t thread_id;
int *client_socket_desc = malloc(sizeof(int));
*client_socket_desc = fd;
pthread_create(&thread_id, NULL, &SocketHandler,(void*) client_socket_desc);
...
Or course you must add error handlings for malloc and pthread_create.
And also free the allocated memory when not needed anymore.
I don't understood why there is the following code in the while loop:
if(send(*client_socket_desc,buffer,1,MSG_NOSIGNAL)>0)
{
puts("closing client socket");
close(*client_socket_desc);
}
Close client sockets in client handler threads.

In if-statement poll() block, function triggered more than once per request

I tried to write simple server in C that uses poll() for testing there's an incoming request in listening socket and create a thread to serve request. In if-statement block of testing fds[0].revents & POLLIN one thread created per request, but printf executed more than once per request.
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct sockaddr_in serverAddr, clientAddr;
struct pollfd fd[1];
socklen_t clientlen;
pthread_attr_t pattr;
int serverfd, optval = 1;
void *accreq(void *);
void make_request_thread();
void sig_handler(int);
int main(int argc, char *argv[])
{
signal(SIGINT, sig_handler);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(80);
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr.s_addr);
serverfd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
bind(serverfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
listen(serverfd, 5);
clientlen = sizeof(clientAddr);
fd[0].fd = serverfd;
fd[0].events = POLLIN;
pthread_attr_init(&pattr);
pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE);
while(1)
{
if(poll(fd, 1, -1) > 0)
{
if(fd[0].revents & POLLIN)
{
printf("Hello!\n"); /* Why this function executed more than once per incoming request*/
make_request_thread();
}
}
}//end while loop
return 0;
}
void *accreq(void *arg)
{
int saccfd = accept(serverfd, (struct sockaddr *)&clientAddr, &clientlen), port, rc, wc;
char buffer[2048], addr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &clientAddr.sin_addr.s_addr, addr, INET_ADDRSTRLEN);
port = ntohs(clientAddr.sin_port);
printf("[Accept request from %s:%i]\n", addr, port);
rc = read(saccfd, buffer, sizeof(buffer));
printf("%s\n", buffer);
wc = write(saccfd, buffer, strlen(buffer));
close(saccfd);
pthread_exit(0);
}
void make_request_thread()
{
pthread_t thread_acc;
pthread_create(&thread_acc, &pattr, accreq, NULL);
}
void sig_handler(int signo)
{
printf("\nCatch signal interrupt\nExiting...\n");
pthread_attr_destroy(&pattr);
close(serverfd);
exit(0);
}
You have a race condition. The race is between your main thread which will call poll() again on the accepting socket, and the spawned thread that will call accept() on that socket. If the spawned thread that calls accept() wins, then the main thread will block (if there is only one incoming connection). If the main thread wins, the poll() call will return immediately, since the socket still has a pending connection waiting to be accepted.
In your code, you don't need to use poll() at all. You can simply block on a call to accept() and and give the spawned thread the newly created socket to process. If you really want poll(), the easiest fix is to call accept() in the main thread after poll() wakes up, and give the newly created socket to the spawned thread.

Resources