recvfrom function is blocked - c

I have following two files
Client.c
int main(void)
{
struct sockaddr_in si_other;
int s, i, slen=sizeof(si_other);
char buf[BUFLEN];
if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
exit(-1);
memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(PORT);
if (inet_aton(SRV_IP, &si_other.sin_addr)==0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
for (i=0; i<NPACK; i++)
{
printf("Sending packet %d\n", i);
sprintf(buf, "This is packet %d\n", i);
if (sendto(s, buf, BUFLEN, 0, &si_other, slen)==-1)
exit(1);
}
sleep(10);
close(s);
return 0;
}
Server.c
int tries=0; /* Count of times sent - GLOBAL for signal-handler access */
void diep(char *s)
{
perror(s);
exit(1);
}
void CatchAlarm(int ignored) /* Handler for SIGALRM */
{
tries += 1;
}
void DieWithError(char *errorMessage)
{}
/* Error handling function */
void *print_message_function( void *ptr )
{
char *message;
usleep(6200*1000);
message = (char *) ptr;
printf("%s \n", message);
sleep(20);
}
int main(void)
{
struct sockaddr_in si_me, si_other;
int s, i, slen=sizeof(si_other);
struct sigaction myAction; /* For setting signal handler */
const char *message1 = "Thread 1====================================";
char buf[BUFLEN];
pthread_t thread1, thread2;
pthread_create( &thread1, NULL, print_message_function, (void*) message1);
if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
diep("socket");
myAction.sa_handler = CatchAlarm;
if (sigfillset(&myAction.sa_mask) < 0) /* block everything in handler */
DieWithError("sigfillset() failed");
myAction.sa_flags = 0;
if (sigaction(SIGALRM, &myAction, 0) < 0)
DieWithError("sigaction() failed for SIGALRM");
memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET;
si_me.sin_port = htons(PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(s, &si_me, sizeof(si_me))==-1)
diep("bind");
alarm(TIMEOUT_SECS);
for (i=0; i<NPACK; i++) {
if (recvfrom(s, buf, BUFLEN, 0, &si_other, &slen)==-1)
{
printf("Inside eagain %d\n",errno);
if(errno == EINTR)
{
alarm(TIMEOUT_SECS); /* Set the timeout */
}
else
exit(-1);
}
else
printf("Received packet from %s:%d\nData: %s\n\n",
inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port), buf);
}
alarm(0);
pthread_join( thread1, NULL);
close(s);
return 0;
}
I am running Server first then Client. In some occurrences Server is not able to receive the message sent my client. Though client sent it successfully. Even EINTR error also I am getting because of alarm but still recvfrom function is getting blocked in between

I solved the problem. The reason is in my system the value of net.core.rmem_max was set to 12KB. And in this case I was sending MBs of data within a very short span of life. So receiver buffer was soon filled up and UDP was ignoring the rest of the buffer. I have increased the net.core.rmem_max to 10MB using following command
sysctl -w net.core.rmem_max=Value
After that this program is working fine.

Related

Why doesn't select() react on received messages?

I'm trying to abort sending UDP data to specific hosts when I receive data back from any of them.
So far what I've tried is creating a thread inside other function that sends data.
Thread is supposed to be checking for incoming data on socket descriptors for maximum of 100 secs. However select() function only waits for timeout and doesn't respond when data is received. Sockets are already created in calling function, here I'm only passing file descriptors. Also this is modified code snippet from Beej's Guide to Network Programming.
void *bot_listen(void *arg){
printf("Thread starting\n");
size_socks *sock_size=(size_socks*)arg;
int n, rv;
fd_set readfds;
struct timeval tv;
thr_running=1;
FD_ZERO(&readfds);
for(int i=0;i<sock_size->size;i++) {
FD_SET(sock_size->sockets[i], &readfds);
}
n = sock_size->size + 1;
tv.tv_usec = 0;
tv.tv_sec = 100;
rv = select(n, &readfds, NULL, NULL, &tv);
if (rv == -1) {
perror("select"); // error occurred in select()
} else if (rv == 0) {
printf("Timeout occurred! No data after 100 seconds.\n");
} else {
bot_recv_message=1;
}
thr_running=0;
}
void send_dgrams(int num_ip, struct message ip_port_pairs, char *message){
struct addrinfo hints, *res;
struct sockaddr_in *dest;
char udp_ip[INET_ADDRSTRLEN];
char str[INET6_ADDRSTRLEN];
char udp_port[22];
char *p;
int *sockfd, time_elapsed=0;
size_socks ss;
printf("Message, beginning of send_dgrams: %s\n", message);
pthread_t listen_thread;
sockfd = (int*)malloc(sizeof(int)*num_ip);
dest = malloc(sizeof(struct sockaddr_in)*num_ip);
p=&(ip_port_pairs.command);
p++;
for(int i =0; i<num_ip;i++) {
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
strcpy(udp_ip, p);
p+=INET_ADDRSTRLEN;
strcpy(udp_port,p);
p+=22;
getaddrinfo(udp_ip, udp_port, &hints, &res);
sockfd[i] = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
dest[i].sin_family = res->ai_family;
dest[i].sin_port = ((struct sockaddr_in *) res->ai_addr)->sin_port;
dest[i].sin_addr = ((struct sockaddr_in *) res->ai_addr)->sin_addr;
memset(dest[i].sin_zero, '\0', sizeof(dest[i].sin_zero));
}
ss.size=num_ip;
ss.sockets=sockfd;
pthread_create(&listen_thread, NULL, bot_listen, (void*)&ss);
while(bot_recv_message==0 && time_elapsed<100) {
for (int i = 0; i < num_ip; i++) {
printf("Sending this message: %s to socket %d\n", message, sockfd[i]);
inet_ntop(AF_INET, &(dest[i].sin_addr), str, INET_ADDRSTRLEN);
printf("Sending to this address: %s\n", str);
printf("Sending to this port: %d\n", ntohs(dest[i].sin_port));
printf("Did bot receive message? :%d\n", bot_recv_message);
sendto(sockfd[i], message, strlen(message) + 1, 0, (struct sockaddr *) &dest[i], sizeof(dest[i]));
}
sleep(1);
time_elapsed+=1;
}
for(int i=0;i<num_ip;i++){
close(sockfd[i]);
}
bot_recv_message=0;
}
This could be the problem:
n = sock_size->size + 1;
...
rv = select(n, &readfds, NULL, NULL, &tv);
Value of the 1st parameter of select() won't be big enough.
Man page of the select() says the following about the 1st parameter:
nfds should be set to the highest-numbered file descriptor in any of
the three sets, plus 1. The indicated file descriptors in each set
are checked, up to this limit (but see BUGS).
So try something like this:
int max_fd = -1;
for(int i=0;i<sock_size->size;i++) {
FD_SET(sock_size->sockets[i], &readfds);
if (sock_size->sockets[i] > max_fd)
max_fd = sock_size->sockets[i];
}
...
rv = select(max_fd + 1, &readfds, NULL, NULL, &tv);

Multipleclient Server: quitfunction

I have some problems with my Server/Client.
If multiple people connect to my server, and one of them quit the connection to the server, all other, which are also connected to the server, lose their connection to.
void *connection_handler(void *);
extern int check_err_buffer(int sock);
extern error_t *error_buffer;
extern invalid_user_input_t invalid_user_input;
regex_t regex;
int main(int argc, char *argv[]) {
//init KVS
init();
int socket_desc, client_sock, c, *new_sock;
struct sockaddr_in server, client;
//Create socket
socket_desc = socket(AF_INET, SOCK_STREAM | O_NONBLOCK, 0);
int opts;
opts = fcntl(socket_desc,F_GETFL);
opts = opts & (~O_NONBLOCK);
fcntl(socket_desc,F_SETFL,opts);
if (socket_desc == -1) {
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(8503);
//Bind
if (bind(socket_desc, (struct sockaddr *) &server, sizeof(server)) < 0) {
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc, 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
while (1) {
puts("waiting for client...");
client_sock = accept(socket_desc, (struct sockaddr *) &client, (socklen_t * ) & c);
puts("Connection accepted");
pthread_t sniffer_thread;
new_sock = malloc(1);
*new_sock = client_sock;
pthread_create(&sniffer_thread, NULL, connection_handler, (void *) new_sock);
//Now join the thread , so that we dont terminate before the thread
//pthread_join(sniffer_thread, NULL);
puts("Handler assigned");
}
if (client_sock < 0) {
perror("accept failed");
return 1;
}
return 0;
}
In the main function I accept the different connection from the clients.
I have more functions, which I didn't put in, because they are not so relevant for this problem.
In the second part I will handle some cases. I look if the client type the letter 'q', if it's true, I will close the connection with close().
But in all cases, it close the server, and all connections are lost.
/*
* This will handle connection for each client
* */
void *connection_handler(void *socket_desc) {
//Get the socket descriptor
int sock = *(int *) socket_desc;
char *message, client_message[3000];
puts("sending welcome msg to client...");
write(sock, message, 3000);
int reti;
//compile a regexp that checks for valid user input
regcomp(&regex, "([dg] [0-9]+)|([v] .+)|(p [0-9]+ .+)|q", REG_EXTENDED);
//Receive a message from client
char *input[3];
while(1){
//wait for some client input
recv(sock, client_message, 2000, 0);
//check the input with the regexp
reti = regexec(&regex, client_message, 0, NULL, REG_EXTENDED);
if (!reti) {
//tokenize the client input with \n as a delim char
char *token = strtok(client_message, " ");
int i = 0;
while (token) {
input[i] = token;
token = strtok(NULL, " ");
i++;
}
//quit operation
if (strcmp(input[0], "q") == 0) {
//if a client quits, the server dies. TODO: fix
puts("quitting");
//free(socket_desc);
close(socket_desc);
return 0;
}
//user input does not match regexp, try again..
} else if (reti == REG_NOMATCH) {
error_buffer = invalid_user_input;
check_err_buffer(sock);
usleep(100);
write(sock, " ", 2);
}
}
//Free the socket pointer
free(socket_desc);
return 0;
}
On the client side i test if message[0] == 'q' and I close the socket.
I would be very happy if i will get some help or hints to solve this problem. Thank you
As here
new_sock = malloc(1);
the code allocates 1 byte only, this following line
*new_sock = client_sock;
writes to invalid memory, as an int is assigned, and sizeof int bytes are written to where new_sock points. By definition sizeof int is at least 2, probably more, With this undefined behaviour is invoked. Anything may happen from then on.
To fix this do
new_sock = malloc(sizeof *new_sock);
instead.
Inspecting the return value of functions is debugging for free. close(socket_desc); is nonsense and definitely would return -1 and set errno to EBADFD.
Replace
close(socket_desc);
by
if (-1 == close(socket_desc))
{
perror("close() falied");
}
to see how the code as it stand fails.

How do I make the program exit when server is disconnected instead of going into an infinte loop?

I have created a server and client communication system in C and when the server is shutdown or quit, the client goes into an infinite loop repeating the last received message instead of quitting. I think the problem lies in recieveMessage function declaration but can't seem to pinpoint it.
How do I resolve this and how can I avoid this in the future?
#include"stdio.h"
#include"stdlib.h"
#include"sys/types.h"
#include"sys/socket.h"
#include"string.h"
#include"netinet/in.h"
#include"netdb.h"
#include"pthread.h"
#define PORT 4444
#define BUF_SIZE 2000
void * receiveMessage(void * socket) {
int sockfd, ret;
char buffer[BUF_SIZE];
sockfd = (int) socket;
memset(buffer, 0, BUF_SIZE);
for (;;) {
ret = recvfrom(sockfd, buffer, BUF_SIZE, 0, NULL, NULL);
if (ret < 0) {
printf("Error receiving data!\n");
break;
} else {
printf("server: ");
fputs(buffer, stdout);
//printf("\n");
}
}
}
int main(int argc, char**argv) {
struct sockaddr_in addr, cl_addr;
int sockfd, ret;
char buffer[BUF_SIZE];
char * serverAddr;
pthread_t rThread;
if (argc > 2) {
printf("usage: client < ip address >\n");
exit(1);
}
serverAddr = argv[1];
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
printf("Error creating socket!\n");
exit(1);
}
printf("Socket created...\n");
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.31.90");
addr.sin_port = PORT;
ret = connect(sockfd, (struct sockaddr *) &addr, sizeof(addr));
if (ret < 0) {
printf("Error connecting to the server!\n");
exit(1);
}
printf("Connected to the server...\n");
memset(buffer, 0, BUF_SIZE);
printf("Enter your messages one by one and press return key!\n");
//creating a new thread for receiving messages from the server
ret = pthread_create(&rThread, NULL, receiveMessage, (void *) sockfd);
if (ret) {
printf("ERROR: Return Code from pthread_create() is %d\n", ret);
exit(1);
}
while (fgets(buffer, BUF_SIZE, stdin) != NULL) {
ret = sendto(sockfd, buffer, BUF_SIZE, 0, (struct sockaddr *) &addr, sizeof(addr));
if (ret < 0) {
printf("Error sending data!\n\t-%s", buffer);
break;
}
puts(buffer);
}
close(sockfd);
pthread_exit(NULL);
return 0;
}
recvfrom returns zero when the other end of the connection is closed, not < 0.
Change your test of the return result as follows:
if (ret == 0)
{
printf("Connection closed!\n");
exit(0);
}
else if (ret < 0) {
printf("Error connecting to the server!\n");
exit(1);
}

Raw Socket Select Event Not occuring

I have sent message from client side and it sent successfully using sendto. But on server side I have created multiple raw sockets, to monitor event on them, used select. But event on rfds not getting noticed by select. Why so? It remains blocked on select system call.
void main()
{
int readSet[2],i;
struct sockaddr_in source;
socklen_t client_addr_size;
//Creating Socket
readSet[0]=socket(AF_INET,SOCK_RAW,221);
readSet[1]=socket(AF_INET,SOCK_RAW,222);
fd_set rfds;
struct timeval tv;
if(readSet[0]==-1 || readSet[1]==-1)
{
perror("\nSocket:");
exit(0);
}
printf("\nSocket Created\n");
memset(&source, 0, sizeof(struct sockaddr_in));
source.sin_family=AF_INET;
source.sin_addr.s_addr=inet_addr("127.0.0.1");
FD_ZERO(&rfds);
while(1)
{
for(i=0; i<2; i++)
FD_SET(readSet[i],&rfds);
printf("\nBefore select\n");
int ret = select(readSet[1]+1, &rfds, NULL, NULL, NULL);
printf("\nRetval:%d\n",ret);
if(ret>0)
{
for(i=0; i<2; i++)
{
if(FD_ISSET(readSet[i],&rfds))
{
char buff[4096];
int ds=0;
if( (ds=recvfrom(readSet[i], buff, 4096, 0, (struct sockaddr *)&source, &client_addr_size)) <0 )
perror("Error in recv: \n");
printf("\nData Receved successfully...%d\n",ds);
printIPHeader((unsigned char *)buff);
break;
}
}//For loop
}
}
sleep(1);
}
//Client siode code
void main()
{
int rsfd1=0,rsfd2;
struct sockaddr_in dest_addr;
socklen_t client_addr_size;
//Creating Socket
rsfd1=socket(AF_INET,SOCK_RAW,221);
rsfd2=socket(AF_INET,SOCK_RAW,221);
if(rsfd1==-1 || rsfd2==-1)
{
perror("\nSocket:");
exit(0);
}
printf("\nSocket Created: \n");
const int val = 1;
if(setsockopt(rsfd1, IPPROTO_IP, IP_HDRINCL, &val, sizeof(val)) < 0)
{
perror("\nsetsockopt() error:");
exit(-1);
}
if(setsockopt(rsfd2, IPPROTO_IP, IP_HDRINCL, &val, sizeof(val)) < 0)
{
perror("\nsetsockopt() error:");
exit(-1);
}
//Constructing IP Header
char buffer[4096];
memset(&buffer,0,sizeof(buffer));
char *msg="Hey there, how are you";
// Our own headers' structures
struct iphdr *iph= (struct iphdr *) buffer;
iph->version=4;
iph->ihl=5;
iph->tos=16;
iph->tot_len=htons(sizeof(iph)+sizeof(msg));
iph->id=0;
iph->ttl=255; //Number of hops
iph->protocol=253;
iph->saddr=inet_addr("127.0.0.1");
iph->daddr=inet_addr("127.0.0.1");
int iphdrlen =iph->ihl*4;
strcat(buffer+iphdrlen,msg);
//End
memset(&dest_addr, 0, sizeof(struct sockaddr_in));
dest_addr.sin_family=AF_INET;
dest_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
printf("\nCustom IP Header to sent...\n");
printIPHeader((unsigned char *)buffer);
int n=0;
if( (n=sendto(rsfd1,buffer,23,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr))) <0 )
perror("Sendto error: ");
char * msg1="I am fine\0";
strcat(buffer+iphdrlen,msg1);
//if( (n=sendto(rsfd2,buffer,23,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr))) <0 )
//perror("Sendto error: ");
printf("\nData Sent Succefully:%d\n",n);
}

UDP multi-client chat server

I have a multi-client chat server and for some reason only the first client is being added. I used a tutorial to help get me started. I have included my code below. When I try and add another client it doesnt appear to be added. If I add one client I get a response from the server like I want but only the first message I enter then after that it stops sending correctly.
Server Code:
int main(void)
{
struct sockaddr_in my_addr, cli_addr[10],cli_temp;
int sockfd;
socklen_t slen[10],slen_temp;
slen_temp = sizeof(cli_temp);
char buf[BUFLEN];
int clients = 0;
int client_port[10];
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
{
printf("test\n");
err("socket");
}else{
printf("Server : Socket() successful\n");
}
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(PORT);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr* ) &my_addr, sizeof(my_addr))==-1)
{
err("bind");
}else{
printf("Server : bind() successful\n");
}
int num_clients = 0;
while(1)
{
//receive
printf("Receiving...\n");
if (recvfrom(sockfd, buf, BUFLEN, 0, (struct sockaddr*)&cli_temp, &slen_temp)==-1)
err("recvfrom()");
if (clients <= 10) {
cli_addr[clients] = cli_temp;
client_port[clients] = ntohs(cli_addr[clients].sin_port);
clients++;
printf("Client added\n");
//printf("%d",clients);
int i;
for(i=0;sizeof(clients);i++) {
sendto(sockfd, buf, BUFLEN, 0, (struct sockaddr*)&cli_addr[i], sizeof(cli_addr[i]));
}
}
}
close(sockfd);
return 0;
}
I have included the client code as well in case it helps.
void err(char *s)
{
perror(s);
exit(1);
}
sig_atomic_t child_exit_status;
void clean_up_child_process (int signal_number)
{
/* Clean up the child process. */
int status;
wait (&status);
/* Store its exit status in a global variable. */
child_exit_status = status;
}
int main(int argc, char** argv)
{
struct sockaddr_in serv_addr;
int sockfd, slen=sizeof(serv_addr);
char buf[BUFLEN];
struct sigaction sigchld_action;
memset (&sigchld_action, 0, sizeof (sigchld_action));
sigchld_action.sa_handler = &clean_up_child_process;
sigaction (SIGCHLD, &sigchld_action, NULL);
int pid,ppid;
if(argc != 2)
{
printf("Usage : %s <Server-IP>\n",argv[0]);
exit(0);
}
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
err("socket");
bzero(&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
if (inet_aton(argv[1], &serv_addr.sin_addr)==0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
pid = fork();
if (pid<0) {
err("Fork Error");
}else if (pid==0) {
//child process will receive from server
while (1) {
bzero(buf,BUFLEN);
//printf("Attempting to READ to socket %d: ",sockfd);
fflush(stdout);
//recvfrom here
if (recvfrom(sockfd, buf, BUFLEN, 0, (struct sockaddr*)&serv_addr, &slen)==-1)
err("recvfrom()");
printf("The message from the server is: %s \n",buf);
if (strcmp(buf,"bye\n") == 0) {
ppid = getppid();
kill(ppid, SIGUSR2);
break;
}
}
}else {
//parent will send to server
while(1){
printf("Please enter the message to send: ");
bzero(buf,BUFLEN);
fgets(buf,BUFLEN,stdin);
printf("Attempting to write to socket %d: ",sockfd);
fflush(stdout);
//send to here
if (sendto(sockfd, buf, BUFLEN, 0, (struct sockaddr*)&serv_addr, slen)==-1)
{
err("sendto()");
}
}
}
close(sockfd);
return 0;
}
Several problems jump out at me. First, every time you receive a message it will consider that to be a new client. Instead of just incrementing the clients variable for a message, you'll need to scan through the array to see if the source address is already present. Second, sizeof(clients) will return a static value (probably 4) depending on how many bytes an int occupies on your machine. That loop should be for( int i = 0; i < clients; i++ ).
You also have a variable named num_clients which is not used. Is that supposed to be there for something and maybe is causing some confusion?
Finally, instead of using the magic value 10 all over the place, use #define MAX_CONNECTIONS 10 and then replace all those numbers with MAX_CONNECTIONS. It's a lot easier to read and change later.

Resources