argc not being 2 error - c

I've been working on a program that was like the one I posted earlier here https://stackoverflow.com/questions/33989328/converting-linked-list-array-client-server-into-single-array except this time I tried to just get the sample code to work making my own program in the process (same basic program but different content) when I get this strange error. In the debugger there is a bit that if argc != 2 it's a usage: client hostname error. I ran it several times and discovered that argc is 1. How do I make argc be 2 and not 1 or 3? There is a client and server program as follows:
edit Now it says connection refused
client:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//define constants
#define SERVER_PORT 6500
#define BUFFER_SIZE 1000
void die(const char*);
void pdie(const char *);
int main (int argc, char *argv[]) {
int sock; // file descriptor (fd) for socket connection
struct sockaddr_in server; // Socket info for server
struct sockaddr_in client; // Socket info about us
int clientLen; // length of client socket struct
struct hostent *hp; // return value from gethostbyname()
char buf[BUFFER_SIZE]; // buffer for message reception from server
int i; // loop counter
if (argc != 2) {
die("Usage: client hostname");
}
for(i = 0; i < 3; i++) {
// Open a socket unbound with type ip/tcp
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
pdie("Opening stream socket");
}
puts("created sock");
// Prepare to connect to server
memset((char*)&server, 0, sizeof(server));
server.sin_family = AF_INET;
if ((hp = gethostbyname(argv[1])) == NULL) {
char msg[100];
sprintf(msg, "%s: unknown host\n", argv[1]);
die(msg);
}
puts("prepared to connect to server");
// set sin_addr struct variables
memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
// IP address should be set to that of the machine running the server
server.sin_addr.s_addr = inet_addr("replace with your ip address");
server.sin_port = htons((u_short) SERVER_PORT);
// Try to connect
socklen_t serverLen = sizeof(server);
if (connect(sock, (struct sockaddr *) &server, serverLen) < 0) {
pdie("connecting stream socket");
}
// Determine what port client is using
clientLen = sizeof(client);
if (getsockname(sock, (struct sockaddr *) &client, &clientLen)) {
pdie("Getting socket name");
}
if (clientLen != sizeof(client)) {
die("getsocketname() overwrote name structure");
}
printf("Client socket has port %hu\n", ntohs(client.sin_port));
// Prepare our buffer for a read
memset(buf, 0, sizeof(buf));
char input[80];
// get initial prompt
read(sock, buf, BUFFER_SIZE);
printf("%s", (char*)buf);
// get user action choice and send to server
scanf("%s", input);
write(sock, (void*)input, strlen(input));
// control for translation choice
if (strncmp(input, "t", 1) == 0) {
// get prompt for word to translate
read(sock, buf, BUFFER_SIZE);
printf("%s", (char*)buf);
// get user word and send to server
scanf("%s", input);
write(sock, (void*)input, strlen(input));
memset(buf, 0, sizeof(buf));
// get translation
read(sock, buf, BUFFER_SIZE);
// output result
if(strncmp((char*)buf, "ERROR", 5) == 0) {
printf("%s\n", (char*)buf);
} else {
printf("%s in Japanese is %s\n", input, (char*)buf);
}
}
// control for add to dictionary choice
else if (strncmp(input, "a", 1) == 0) {
// get prompt for eng word
memset(buf, 0, sizeof(buf));
read(sock, buf, BUFFER_SIZE);
// get eng word from user
printf("%s", (char*)buf);
scanf("%s", input);
// send eng word to server
write(sock, (void*)input, strlen(input));
memset(buf, 0, sizeof(buf));
// get prompt for Japanese word
read(sock, buf, BUFFER_SIZE);
printf("%s", (char*)buf);
scanf("%s", input);
// send Japanese word to server
write(sock, (void*)input, strlen(input));
// get result
memset(buf, 0, sizeof(buf));
read(sock, buf, BUFFER_SIZE);
printf("%s\n", (char*)buf);
}
// Close this connection
close(sock);
}// end for loop
exit(0);
}// end main
// Call perror() to figure out what's going on and die
void pdie(const char *mesg) {
perror(mesg);
exit(1);
}
// Print a message and die
void die(const char *mesg) {
fputs(mesg, stderr);
fputc('\n', stderr);
exit(1);
}
and server
#define _REENTRANT
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/uio.h>
#include <unistd.h>
#include <pthread.h>
// constant declarations
#define TCP_PORT 6500
#define BUFFER_SIZE 1000
// variable declarations
pthread_mutex_t lock;
int serve_count;
// used to store eng word and translation
typedef struct wordpair* wordPairPtr;
struct wordPair
{
char* eng;
char* jap;
wordPairPtr nextPair;
};
typedef struct wordPair wordPair;
// used to store all word pairs in a directory
// implemented as a linked list
struct directory
{
wordPair* dict;
int num_words;
};
typedef struct directory directory;
// function prototypes
void* doKid(void*);
void initializeDirect();
int directAdd(char*, char*);
char* translate(char*);
// global directory variable
directory* d;
main ()
{
// variable declarations
int sockfd;
int newsockfd;
int client;
struct sockaddr_in cli_addr, serv_addr;
pthread_t chld_thr;
initializeDirect();// call function to create directory
puts ("initialized variables");
// build thread attributes
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
puts("set thread attributes");
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
fprintf(stderr, "server: can't open stream socket\n");
exit(0);
}
puts("opened stream socket");
// set serv_addr struct variables
memset((char*) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(TCP_PORT);
puts("did serv_addr actions");
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0 )
{
fprintf(stderr, "server: can't bind local address\n");
exit(0);
}
puts("bound local address");
// set the level of thread concurrency we desire
pthread_setconcurrency(5);
listen(sockfd, 5);
puts("set thread concurrency");
// begin listening for client requests
puts("awaiting requests");
for(;;)
{
client = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &client);
if (newsockfd < 0)
{
fprintf(stderr, "server: accept error\n");
exit(0);
}
// create a new thread to process the incoming request
pthread_create(&chld_thr, &attr, doKid, (void*)newsockfd);
puts("Created thread");
// the server is now free to accept another socket request
}
free(d);
puts("now exiting");
return(0);
}// end main
// allocates memory for directory and stores small set of preloaded words and phrases
void initializeDirect()
{
d = (directory*)malloc(sizeof(directory));
if (d == NULL)
{
exit(1);
}
char *eng[20] = {"good morning", "good afternoon", "good evening", "good-bye",
"good night)", "thank you", "no", "yes",
"I'll go and come back", "I'm home", "mother", "father", "older sister", "older brother", "younger sister", "younger brother", "god", "boy", "girl", "spirit"
};
char *jap[20] = {"ohaiyou", "konnichiwa", "konbanwa", "sayonara",
"oyasumi(nasai)", "arigatou", "iie", "hai",
"ittekimasu", "tadaima", "okaasan", "otousan", "oneesan", "oniisan", "imouto", "otouto", "kami", "shoenen", "shoujo", "genki"
};
int i;
for(i = 0; i < 10; i++)
{
directAdd(eng[i], jap[i]);
}
}// end initializeDirect()
// adds a new word pair alphabetically into the directory
int directAdd(char* eng, char* jap)
{
// test for valid arguments
if (eng == NULL || jap == NULL)
{
return (-1);
}
// allocate memory for new wordPair
wordPair *newPair = (wordPair*)malloc(sizeof(wordPair));
if(newPair == NULL)
return(-1);
// assign passed values to new wordPair
newPair->eng = eng;
newPair->jap = jap;
newPair->nextPair = NULL;
// if this is the first wordPair, add it to the front of the linked list
if(d->dict == NULL)
{
d->dict = newPair;
return 0;
}
// otherwise, search directory for correct location for new word pair
wordPair *current = d->dict;
wordPair *previous = NULL;
while(current != NULL && (strcasecmp(current->eng, newPair->eng) < 0))
{
previous = current;
current = current->nextPair;
}
// if the new word is last in the directory, add it there
if(current == NULL)
{
previous->nextPair = newPair;
return 0;
}
// if the english word is already in the directory, return -2
if(strcasecmp(current->eng, newPair->eng) == 0)
{
free(newPair);
return -2;
}
// if the new word is first in the directory, add it there
if(previous == NULL)
{
newPair->nextPair = d->dict;
d->dict = newPair;
return;
}
// if none of the special cases occurred, add the new word
newPair->nextPair = current;
previous->nextPair = newPair;
// advance total count of words
d->num_words++;
// return success
return 0;
}
char* translate(char* eng)
{
// check that our directory is valid
if (d == NULL || d->dict == NULL)
return NULL;
// start searching at the beginning of the directory
wordPair *current = d->dict;
// loop until we find the word or reach the end of the directory
while(current != NULL && strcasecmp(current->eng, eng) < 0)
{
current = current->nextPair;
}
// the word is not in the directory
if(current == NULL)
{
return NULL;
}
// we found the word, return the translation
if( strcasecmp(current->eng, eng) == 0)
{
return strdup(current->jap);
}
// there was an error, return null
return NULL;
}// end translate
// this is the routine that is executed from a new thread
void *doKid(void* arg)
{
int mysocfd = (int) arg;
char buf[BUFFER_SIZE];
char *eng;
char *jap;
char *msg;
int i;
// allocate strings
memset(buf, 0, BUFFER_SIZE);
eng = (char*)malloc(sizeof(char[20]));
jap = (char*)malloc(sizeof(char[20]));
msg = (char*)malloc(sizeof(char[100]));
// build and send intro prompt for client
msg = "Would you like to translate or add a word? (t/a): ";
write(mysocfd, (void*)msg, strlen(msg));
// read from the given socket
read(mysocfd, buf, BUFFER_SIZE);
// if the client wants to translate a word
if(strncmp((char*)buf, "t", 1) == 0)
{
// build and send prompt for word to translate
msg = "Enter the English word you would like to translate to jap: ";
write(mysocfd, (void*)msg, strlen(msg));
// receive word
read(mysocfd, buf, BUFFER_SIZE);
strcpy(eng, buf);
// execute translation
char *trans;
trans = (char*)malloc(sizeof(char[20]));
// lock global variable for read
pthread_mutex_lock(&lock);
trans = translate((char*)buf);
pthread_mutex_unlock(&lock);
// if word was not in directory send error msg to client
if (trans == NULL)
{
msg = "ERROR: word is not in the directory.";
write(mysocfd, (void*)msg, strlen(msg));
}
// if word was translated, send result to client
else
{
write(mysocfd, (void*)trans, strlen(trans));
}
}
// if the client wants to add a word
else if (strncmp((char*)buf, "a", 1) == 0)
{
// build and send prompt for english word
msg = "Enter the English word to add: ";
write(mysocfd, (void*)msg, strlen(msg));
// receive word
read(mysocfd, buf, BUFFER_SIZE);
strcpy(eng, buf);
// build and send prompt for jap translation
memset(buf, 0, sizeof(buf));
msg = "Enter the translation to jap: ";
write(mysocfd, (void*)msg, strlen(msg));
// receive translation
memset(buf, 0, sizeof(buf));
read(mysocfd, buf, BUFFER_SIZE);
strcpy(jap, buf);
// lock global variable for word insertion
pthread_mutex_lock(&lock);
int result = directAdd(eng, jap);
pthread_mutex_unlock(&lock);
// if the add to directory was successful, alert client
if (result == 0)
{
msg = "Added to directory";
}
// if the add to directory was unsuccessful send client error msg
else if (result == -2)
{
msg = "Word is already in directory";
}
else
{
msg = "ERROR.";
}
write(mysocfd, (void*)msg, strlen(msg));
}
// if no valid choice was sent by client, exit thread
else
{
close(mysocfd);
pthread_exit(0);
}
printf("Child[%lu]: Done Processing...\n", pthread_self());
// use a mutex to update the global service counter
pthread_mutex_lock(&lock);
serve_count++;
pthread_mutex_unlock(&lock);
printf("Kid thread [%lu]: The total sockets served = %d\n", pthread_self(), serve_count);
// close the socket and exit this thread
close(mysocfd);
pthread_exit(0);
}// end doKid()

Related

Socket connection refused, but both client and server work independently

I've implemented a network chat client in C that looks like this:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "stdbool.h"
#include "sys/socket.h"
#include "sys/types.h"
#include "netdb.h"
#include "netinet/in.h"
#include "pthread.h"
#include "errno.h"
#define MESSAGE_BUFFER 500
#define USERNAME_BUFFER 10
typedef struct {
char* prompt;
int socket;
} thread_data;
// Connect to server
void * connect_to_server(int socket_fd, struct sockaddr_in *address) {
int response = connect(socket_fd, (struct sockaddr *) address, sizeof *address);
if (response < 0) {
fprintf(stderr, "socket() failed: %s\n", strerror(errno));
printf("Failed to connect\n");
exit(1);
} else {
printf("Connected\n");
}
}
// Get message from stdin and send to server
void * send_message(char prompt[USERNAME_BUFFER+4], int socket_fd, struct sockaddr_in *address) {
printf("%s", prompt);
char message[MESSAGE_BUFFER];
char final_message[MESSAGE_BUFFER+USERNAME_BUFFER+1];
while (fgets(message, MESSAGE_BUFFER, stdin) != NULL) {
memset(final_message,0,strlen(final_message)); // Clear final message buffer
strcat(final_message, prompt);
strcat(final_message, message);
printf("\n%s", prompt);
if (strncmp(message, "/quit", 5) == 0) {
printf("Closing connection...\n");
exit(0);
}
sendto(socket_fd, final_message, MESSAGE_BUFFER+USERNAME_BUFFER+1, 0, (struct sockaddr *) &address, sizeof address);
}
}
void * receive(void * threadData) {
int socket_fd, response;
char message[MESSAGE_BUFFER];
thread_data* pData = (thread_data*)threadData;
socket_fd = pData->socket;
char* prompt = pData->prompt;
memset(message, 0, MESSAGE_BUFFER); // Clear message buffer
// Print received message
while(true) {
response = recvfrom(socket_fd, message, MESSAGE_BUFFER, 0, NULL, NULL);
if (response) {
printf("\nServer> %s", message);
printf("%s", prompt);
fflush(stdout); // Make sure "User>" gets printed
}
}
}
int main(int argc, char**argv) {
long port = strtol(argv[2], NULL, 10);
struct sockaddr_in address, cl_addr;
char * server_address;
int socket_fd, response;
char prompt[USERNAME_BUFFER+4];
char username[USERNAME_BUFFER];
pthread_t thread;
// Check for required arguments
if (argc < 3) {
printf("Usage: client ip_address port_number\n");
exit(1);
}
// Get user handle
printf("Enter your user name: ");
fgets(username, USERNAME_BUFFER, stdin);
username[strlen(username) - 1] = 0; // Remove newline char from end of string
strcpy(prompt, username);
strcat(prompt, "> ");
server_address = argv[1];
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(server_address);
address.sin_port = port;
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
connect_to_server(socket_fd, &address);
// Create data struct for new thread
thread_data data;
data.prompt = prompt;
data.socket = socket_fd;
// Create new thread to receive messages
pthread_create(&thread, NULL, receive, (void *) &data);
// Send message
send_message(prompt, socket_fd, &address);
// Close socket and kill thread
close(socket_fd);
pthread_exit(NULL);
return 0;
}
This works perfectly fine with a server that I wrote for it. However, when I try to make it play nicely with a server in another language, or one that someone else wrote, things fall apart, and I can't establish a connection. Shouldn't these work independently from each other? If both work separately, they should work together, from what I gather.
For example, if I try to use my client with the server in the answer to this question, things no longer work. I've tested both of them, and they work fine separately, just not together. I've looked at the output of stderr when connecting, but all I get is a Connection refused error with no more information.
Is there something obvious I'm missing trying to get these to work together? If someone could demonstrate how my client could work with the example server, that would be super helpful.
address.sin_port = port;
The problem is here. It should be
address.sin_port = htons(port);
in both client and server.
There are other problems.
fprintf(stderr, "socket() failed: %s\n", strerror(errno));
This should be
fprintf(stderr, "connect() failed: %s\n", strerror(errno));
Then:
sendto(socket_fd, final_message, MESSAGE_BUFFER+USERNAME_BUFFER+1, 0, (struct sockaddr *) &address, sizeof address);
This should be:
send(socket_fd, final_message, strlen(final_message)+1, 0);
You don't need sendto(), as you are already connected, and you don't need to send anything beyond the trailing null. As a matter of fact you can reduce the entire method to this:
void * send_message(char prompt[USERNAME_BUFFER+4], int socket_fd, struct sockaddr_in *address) {
printf("%s", prompt);
char message[MESSAGE_BUFFER];
while (fgets(message, MESSAGE_BUFFER, stdin) != NULL) {
if (strncmp(message, "/quit", 5) == 0) {
printf("Closing connection...\n");
close(socket_fd);
exit(0);
}
send(socket_fd, prompt, strlen(prompt), 0);
send(socket_fd, message, strlen(message)+1, 0);
printf("\n%s", prompt);
}
}
Then:
if (response) {
printf("\nServer> %s", message);
printf("%s", prompt);
fflush(stdout); // Make sure "User>" gets printed
}
That should be:
if (response == -1) {
fprintf(stderr, "recv() failed: %s\n", strerror(errno));
break;
} else if (response == 0) {
printf("\nPeer disconnected\n");
break;
} else {
printf("\nServer> %s", message);
printf("%s", prompt);
fflush(stdout); // Make sure "User>" gets printed
}

I am getting a Operation not supported error

I am using Ubuntu on virtual box and I have a virtual hangman game using a server and client. Multiple clients can connect to the server at once but when the the game is finished this is the error that comes up on the server "accepting connection:Operation not supported"
Here is my code
#include <sys/types.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <syslog.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
extern time_t time ();
int maxlives = 12;
char *word [] = {
# include "words"
};
# define NUM_OF_WORDS (sizeof (word) / sizeof (word [0]))
# define MAXLEN 80 /* Maximum size in the world of Any string */
# define HANGMAN_TCP_PORT 1066
int main ()
{
int sock, fd, client_len;
pid_t pid;
struct sockaddr_in server, client;
srand ((int) time ((long *) 0)); /* randomize the seed */
sock = socket (AF_INET, SOCK_STREAM, 0);//0 or IPPROTO_TCP
if (sock <0) { //This error checking is the code Stevens wraps in his Socket Function etc
perror ("creating stream socket");
exit (1);
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(HANGMAN_TCP_PORT);
if (bind(sock, (struct sockaddr *) & server, sizeof(server)) <0) {
perror ("binding socket");
exit (2);
}
listen (sock, 5);
while (1) {
client_len = sizeof (client);
if ((fd = accept (sock, (struct sockaddr *) &client, &client_len)) <0)
{
perror ("accepting connection");
exit (3);
}
else
{
//make a child using fork();
// fork();
pid = fork();
//if id == 0, it is child
if(pid ==0)
{
//close the listening port, play hangman
close(sock);
play_hangman (fd, fd);
close(fd);
}
//else, it is parent, ignore child and guest, listen for more guests to make more children with
else {
close (fd);
}
}
}
close(fd);
}
/* ---------------- Play_hangman () ---------------------*/
play_hangman (int in, int out)
{
char * whole_word, part_word [MAXLEN],
guess[MAXLEN], outbuf [MAXLEN];
int lives = maxlives;
int game_state = 'I';//I = Incomplete
int i, good_guess, word_length;
char hostname[MAXLEN];
gethostname (hostname, MAXLEN);
sprintf(outbuf, "Playing hangman on host% s: \n \n", hostname);
write(out, outbuf, strlen (outbuf));
/* Pick a word at random from the list */
whole_word = word[rand() % NUM_OF_WORDS];
word_length = strlen(whole_word);
syslog (LOG_USER | LOG_INFO, "server chose hangman word %s", whole_word);
/* No letters are guessed Initially */
for (i = 0; i <word_length; i++)
part_word[i]='-';
part_word[i] = '\0';
sprintf (outbuf, "%s %d \n", part_word, lives);
write (out, outbuf, strlen(outbuf));
while (game_state == 'I')
/* Get a letter from player guess */
{
while (read (in, guess, MAXLEN) <0) {
if (errno != EINTR)
exit (4);
printf ("re-read the startin \n");
} /* Re-start read () if interrupted by signal */
good_guess = 0;
for (i = 0; i <word_length; i++) {
if (guess [0] == whole_word [i]) {
good_guess = 1;
part_word [i] = whole_word [i];
}
}
if (! good_guess) lives--;
if (strcmp (whole_word, part_word) == 0)
game_state = 'W'; /* W ==> User Won */
else if (lives == 0) {
game_state = 'L'; /* L ==> User Lost */
strcpy (part_word, whole_word); /* User Show the word */
}
sprintf (outbuf, "%s %d \n", part_word, lives);
write (out, outbuf, strlen (outbuf));
}
}
I found out the problem seems to be here
//HERE
while (1) {
client_len = sizeof (client);
if ((fd = accept (sock, (struct sockaddr *) &client, &client_len)) <0)
{
perror ("accepting connection");
exit (3);
}
else
{
//make a child using fork();
// fork();
pid = fork();
//HERE
But I don't know what is wrong or how to fix this error.
You should terminate child process when the game becomes finished. But instead you are trying to iterate over accept() loop using already closed sock descriptor:
if(pid == 0)
{
//close the listening port, play hangman
close(sock);
play_hangman (fd, fd);
// child has done its job, terminate immediately
_Exit(0);
}
//else, it is parent, ignore child and guest, listen for more guests to make more children with
else {
close (fd);
}
Probably when your child is running play_hangman() value that is stored in sock may be reused for some another file, since we've closed that descriptor before. And that new file is definitely not a listening socket. As result accept() fails with Operation not supported.

UDP chat application in C - IP prints as 0.0.0.0

I have created a UDP chat application using state machine pattern but when it needs to print the IP address using inet_ntoa, the terminal displays 0.0.0.0.
Here is my entire code (I am pasting it whole so you can tell me where I can improve it. I started learning C two weeks ago and could REALLY use some advice)
#include <stdio.h> // stdin, fgets(), scanf(), printf()
#include <stdlib.h> // exit()
#include <sys/socket.h> // SOCK_DGRAM
#include <netinet/in.h> // in_addr
#include <arpa/inet.h> // inet_ntoa(), inet_aton()
#include <unistd.h> // select()
#include <string.h> // memset(), strcpy(), strerror()
#include <errno.h> // errno
#include <ctype.h> // isspace()
#define LISTENER_PORT 48879 // our 0xBEEF port :-)
#define BUFFER_SIZE 204 // 200 bytes plus 4 bytes of header
#define STDIN 0 // keyboard input
int chat_socket; // this is the only socket used in the program
typedef struct // struct the protocol
{
unsigned char version; // 1 byte version number
unsigned char command; // 1 byte command type
unsigned char seq; // 1 byte sequence number
unsigned char ack; // 1 byte acknowledgment number
char data[BUFFER_SIZE]; // 200 bytes message limit
} Packet;
Packet rxPacket; // received packet instance
Packet txPacket; // sent packet instance
enum states // enumerate the states
{
START, // Send request to remote IP or wait for a request (WAIT_CONN_REQ)
WAIT_RESP, // Chat request sent to remote IP. Waiting for a response from the target machine
SEND_CONN_RESP, // Chat request received from remote IP. ACCEPT or REJECT
ACCEPTED, // Both parties agreed to exchange datagrams. Begin application data (MESSAGES) exchange
STOP
};
typedef enum states states;
states state;
struct sockaddr_in my_address;
struct sockaddr_in sender_address;
struct sockaddr_in dest_address;
ssize_t r;
socklen_t sockLen = sizeof(struct sockaddr_in);
int WAIT_CONN_REQ(char *argv[])
{
/* Bind the socket to the given port */
if (bind(chat_socket, (struct sockaddr *)&my_address, sizeof(my_address))<0)
{
printf("UDP socket bind() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
printf("Socket bound to port %d!\nWaiting for CONN_REQ!\n", LISTENER_PORT);
if (((r = recvfrom(chat_socket, &rxPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, &sockLen)))<0)
{
printf("UDP recvfrom() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
if (rxPacket.command == 1)
{
int rsp = 0;
char q = 0;
while (q != 'A' && q != 'D')
{
printf("Connection request received from %s - [A]ccept or [D]ecline?\t", inet_ntoa(sender_address.sin_addr));
scanf(" %c", &q);
}
if (q == 'A')
{
printf("You have accepted the connection request.\n");
rsp = 3;
}
else if (q == 'D')
{
printf("You have declined the connection request.\n");
rsp = 2;
}
if (rsp != 0)
{
strcpy(txPacket.data, "Name");
txPacket.version = 1;
txPacket.command = rsp;
sendto(chat_socket, &txPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, sizeof(sender_address));
state = ACCEPTED;
}
}
return(0);
}
void lookup(FILE *names, struct sockaddr_in myip[])
{
char ipNr[32];
char chatName[32];
while(!feof(names))
{
fscanf(names, "%[^;];%s\n", ipNr, chatName);
if (strcmp(ipNr, (const char*) myip) == 0)
{
printf("Found your IP in database\n");
printf("IP: %s\n", ipNr);
printf("Username: %s\n", chatName);
printf("---\n");
return;
}
}
}
void SEND_CONN_REQ(char *argv[])
{
strcpy(txPacket.data, "Name");
txPacket.version = 1;
txPacket.command = 1;
printf("Dest IP is %s\n", argv[0]);
inet_aton(argv[0], &dest_address.sin_addr);
sendto(chat_socket, &txPacket, BUFFER_SIZE, 0, (struct sockaddr *)&dest_address, sizeof(dest_address));
printf("Chat request sent to %s - Waiting for a response\n", inet_ntoa(dest_address.sin_addr));
state = WAIT_RESP;
}
void initialise()
{
memset(&my_address.sin_zero, 0, sizeof(my_address.sin_zero));
memset(&dest_address.sin_zero, 0, sizeof(dest_address.sin_zero));
memset(&sender_address.sin_zero, 0, sizeof(sender_address.sin_zero));
my_address.sin_family = AF_INET;
my_address.sin_addr.s_addr = INADDR_ANY;
my_address.sin_port = htons(LISTENER_PORT);
dest_address.sin_family = AF_INET;
dest_address.sin_port = htons(LISTENER_PORT);
if ((chat_socket = socket(AF_INET, SOCK_DGRAM, 0))<0)
{
printf("UDP socket allocation error no %d: %s\n", errno, strerror(errno));
exit(1);
}
}
void DATA_XCHANGE()
{
while (1)
{
txPacket.version = 1;
txPacket.command = 0;
int len = sizeof(sender_address);
fd_set readSet;
FD_ZERO(&readSet);
FD_SET(STDIN, &readSet);
FD_SET(chat_socket, &readSet);
if ((select(32, &readSet, NULL, NULL, NULL))>0)
{
if (FD_ISSET(STDIN, &readSet))
{
fgets(txPacket.data, BUFFER_SIZE, stdin);
if (isspace(*txPacket.data) == 0)
{
printf("You: %s", txPacket.data);
sendto(chat_socket, &txPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, sizeof(sender_address));
}
}
else if (FD_ISSET(chat_socket, &readSet))
{
if (((r = recvfrom(chat_socket, &rxPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, (socklen_t *)&len)))<0)
{
printf("UDP recvfrom() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
if (rxPacket.command == 0)
{
printf("message: %s", rxPacket.data);
}
}
}
}
}
int main(int argc, char *argv[])
{
initialise();
printf("your ip is %s", inet_ntoa(my_address.sin_addr));
char *fname = "names.db";
FILE *names = fopen(fname, "r");
lookup(names, &my_address);
state = START;
while (state != STOP)
{
switch (state)
{
case START:
printf("Simple Chat Client - START state\n");
if (argv[1] != NULL)
{
SEND_CONN_REQ(&argv[1]);
}
else
{
WAIT_CONN_REQ(&argv[1]);
}
break;
case WAIT_RESP:
printf("WAIT_RESP STATE!\n");
if (((r = recvfrom(chat_socket, &rxPacket, BUFFER_SIZE, 0, (struct sockaddr *)&sender_address, &sockLen)))<0)
{
printf("UDP recvfrom() error no %d: %s\n", errno, strerror(errno));
exit(1);
}
if (rxPacket.command == 3)
{
printf("Your connection request was accepted.\n");
state = ACCEPTED;
}
else if (rxPacket.command == 2)
{
printf("Your connection request was declined.\n");
state = STOP;
}
break;
case SEND_CONN_RESP:
printf("SEND_CONN_RESP state!\n");
break;
case ACCEPTED:
printf("ACCEPTED state!\n");
DATA_XCHANGE();
break;
case STOP:
printf("STOPPED! (switch)\n");
break;
}
}
printf("STOPPED! main()\n");
}
The printf() right below initialise() in the main() function is where it prints 0.0.0.0
Again, I would VERY MUCH appreciate any coding advice at this point. It helps the learning process!
Your program is doing exactly what it's supposed to.
0.0.0.0 is the value of INADDR_ANY -- in other words, bind to all available interfaces.
When you set it here:
my_address.sin_addr.s_addr = INADDR_ANY;
you're setting it to 0, and telling it to bind to anything it can.

Problems while implementing HTTP 1.0 server

I am trying to implement a simple HTTP server with C that
reads a request
checks if it is a GET request
reads the URL from the request
Checks if file is on server and tries to open it
I am using strtok for String tokenizing and I think it messes up the filepath. open and fopen always return error codes and are not able to open any files.
Here is my code:
/*
** parser.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define MYPORT 3499 // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold
#define MAXLEN 1024 //upper limit of the length of the string
int main(void)
{
char input[MAXLEN]; //the line that is read from the client
char * token1; //GET request
char * token2; //filepath
char tmpstring[MAXLEN]; //filesize
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd, file open on file_fd
struct sockaddr_in my_addr; // my address information
struct sockaddr_in their_addr; // connector's address information
int sin_size;
int yes=1;
int n; //the amount of read characters from the client
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
my_addr.sin_family = AF_INET; // host byte order
my_addr.sin_port = htons(MYPORT); // short, network byte order
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
memset(&(my_addr.sin_zero), '\0', 8); // zero the rest of the struct
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
perror("bind");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
while(1) { // main accept() loop
sin_size = sizeof(struct sockaddr_in);
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
perror("accept");
continue;
}
printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));
n = readline(new_fd, input, MAXLEN); //n is the amount of read characters
if (n == -1) {
perror("Unable to read line");
}
//Check if it is a GET message
token1 = strtok(input," ");
if(strcmp(token1, "GET") != 0)
{
send(new_fd, "Bad request\n", 30, 0);
}
else
{
//Retrieve the file path
token2 = strtok(NULL, " ");
if(token2 == NULL)
{
send(new_fd, "File path not specified\n", 23, 0); //Check if filename is empty
}
send(new_fd, token2, strlen(token2), 0); //test
printf("%s", token2);
if(token2[0] == '/') //remove the initial slash
memmove(token2, token2 + 1, strlen(token2));
//char * path = "test.html"; //test line
//char * buff;
//int len = sprintf(buff, "1: %d 2: %d\n", strlen(token1), strlen(token2));
//send(new_fd, buff, len, 0);
//Check if file is on the server
if(open(token2, O_RDONLY) < 0) //Error opening file
{
if(errno == EACCES)
send(new_fd, "Access error\n", 30, 0);
else
send(new_fd, "Not existed\n", 30, 0);
}
else
{
FILE * requested_file = fopen(token2, "r");
if(requested_file == NULL) //
{
send(new_fd, "Error in fopen\n", 30, 0);
}
else
{
send(new_fd, "File found\n", 30, 0); //successful
}
fseek(requested_file, 0, SEEK_END); // move to the end of the file
int end= ftell(requested_file); // get the position of the end of file
int stringlen = sprintf(tmpstring, "file size: %d\n", end);
send(new_fd, tmpstring, stringlen, 0);
}
}
close(new_fd); //close connection
}
return 0;
}
//helper function for recieving text
int readline(int fd, char *buf, int maxlen)
{
int n, rc;
char c;
for (n = 1; n < maxlen; n++) {
if ((rc = read(fd, &c, 1)) == 1) {
*buf++ = c;
if (c == '\n')
break;
} else if (rc == 0) {
if (n == 1)
return 0; // EOF, no data read
else
break; // EOF, read some data
} else
return -1; // error
}
*buf = '\0'; // null-terminate
return n;
}
So I'm placing a test.html in the same folder as the server. Then im telnetting to localhost and port 3499. This is the output when entering GET /test.html:
/test.html
Not existed
rError in fopen
Connection closed by foreign host.
try opening "test.html" instead of "\test.html"

Select function behavior - Multi Client Quiz

I have to build a quiz application.
Details about the application:
1. Each client has to register to server before participating in Quiz. The server will ask
username from each user and generate temporary id for each user.
2. After Registration process clients, who are successfully connected to server will get
Question from server.
3. The client will reply with answer.
4. Server will receive answer from different clients with time stamps, and it will calculate
time difference of each client which is called ∆t.
Define such as:
∆t = (Time Question sent - Time answer received) - RTT
Where RTT is Round Trip Time
Server will select client, whose ∆t is minimum to all and reply with whatever score client will gain remains will not gain any score.
After sending Question server will wait Answer for a particular time periods called (T). If client did not reply within ‘T’ time period Server will skip that Question and goes to next Question.
Pseudocode of main loop in my server code
A. A main while loop which runs once for each question.
B. Inside this first I am accepting login for 10 seconds.
Here I am assigning user Id and all other initialization stuff.
C. Then using `select` to check which are available for writing.
To available connections I am checking `RTT` and then sending question to each user.
D. Then I am waiting for some time to get answers.
Here I am using `select` to determine where the answer is available to read.
E. Then I am repeating steps C. and D.
Problem:
When I connect only to a single client my code works fine for any number of question.
But when I test this code on multiple client with the same client code:
Login for everyone is OK.
Sending First Question to everyone works fine.
Then while waiting for the answer I only received answer from one client. Each client shows that answer is been sent. For second client the second select function doesn't return with readable data availability.
Why for multi-client my code is not working. (According to me the error is somewhere in getting answer).
My Code:
The structure of the packets send can be understand easily from the variable names.
Server.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.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>
#include <time.h>
#define PORT "3490" //the port user will be connecting to
#define BACKLOG 10 //how many pending connection queue will hold
#define maxUser 10
#define LOGIN_OK "OK"
#define LOGIN_WrongPassword "NP"
#define LOGIN_WrongUsername "NU"
#define MAX_USERS 10
#define MAX_ANSWER_TIME 10
#define LOGIN_WAIT 10
#define TOTAL_QUES "3"
int users[MAX_USERS][3] = {}; //index is userID, 0 is no user
void sigchld_handler(int s)
{
while(waitpid(-1, NULL, WNOHANG) > 0);
}
//get sockaddr, IPv4 or IPv6
int timer;
void alarm_handler(int s) {
timer = 0;
}
wrongRecv(ssize_t recvd, ssize_t expctd)
{
if(recvd != expctd)
{
printf("Recvd(%zd) bytes not equal to expected(%zd) bytes\n",recvd,expctd);
//getchar();
}
}
//void nextQues(char* quesMsg, char* ques, char* optA, char* optB, char* optC, char* optD)
int nextQues(char* quesMsg, int QID)
{
char ques[40], optA[10], optB[10], optC[10], optD[10], quesId[5];
sprintf(quesId,"%d",QID);
strncpy(ques, "This is the question?",22);
strncpy(optA, "OptionA", 7); strncpy(optB, "OptionB", 7); strncpy(optC, "OptionC", 7); strncpy(optD, "OptionD", 7);
strncpy(quesMsg,quesId,5);
strncpy(quesMsg + 05,ques,40);
strncpy(quesMsg + 45,optA,10);
strncpy(quesMsg + 55,optB,10);
strncpy(quesMsg + 65,optC,10);
strncpy(quesMsg + 75,optD,10);
return 0;
}
//void answerCheck(char* ques, char* optA, char* optB, char* optC, char* optD, char* usrResponse, int rtt, int timeTaken)
void answerCheck(int fd, char usrResponse[6], int rtt, int timeTaken)
{
int responseTime, i;
char actualAnswer[1];
char quesId[5];
printf("fd(%d) quesid(%s) response(%c) rtt(%d) timeTaken(%d)\n", fd, usrResponse, usrResponse[5], rtt, timeTaken );
strncpy(quesId, usrResponse, 5);
actualAnswer[0] = 'B';//we have quesId we can find actual answer on basis of it
if(actualAnswer[0] == usrResponse[5])
{
//printf("%s\n","+++++" );
responseTime = timeTaken - rtt;
//printf("Response Time(%d)\n",responseTime);
//save it with user id
//finding userid
for(i = 0; i < MAX_USERS; i++) {
if(users[i][1] == fd) {
users[i][2] = responseTime;//saving it
//printf("%d\n",i );
}
}
}
}
int compareAnswer() {
int i, min = 2 * MAX_ANSWER_TIME, userIndex;
for(i = 0; i < MAX_USERS; i++) {
if(users[i][2] < min) {
min = users[i][2];
userIndex = i;
}
}
//Increasing Score
users[userIndex][0]++;
//returning fd
return users[userIndex][1];
}
void users_deleteFd(int fd) {
int i;
for (i = 0; i < MAX_USERS; ++i)
{
if(users[i][1] == fd) {
users[i][1] =0;
return;
}
}
}
int rtt_check(int new_fd)
{
ssize_t send_ret, recv_ret;
char rtt_check[1];
time_t rtt1, rtt2;
rtt1 = time(NULL);
send_ret = send(new_fd, "r", 1, 0);
if(send_ret == 0)
{
return -2;
}
wrongRecv(send_ret, 1);
//printf("%s\n","Between two phase of rttCheck" );
recv_ret = recv(new_fd, rtt_check, 1,0);
rtt2 = time(NULL);
if(recv_ret == 0)
{
return -2;
}
wrongRecv(recv_ret,1);
//printf("diff(%d)\n",(int) difftime(rtt2,rtt1));
return (int) difftime(rtt2,rtt1);
}
int login(char user[], char pass[])
{
//for user
static int Id = 0; //when have function getUserID, make it not static and also remove Id++;
if(!strcmp(user,"abhishek") && !strcmp(pass,"abhishek")) {
//Id = getUserID(user);
return ++Id;
}else if(!strcmp(user,"abhishek")){
return 0; //wrong password
}
return -1; //wrong username
}
int totalQues;
int login_setup(int new_fd)
{
//login inititalizations
char login_det[16];
char username[9],password[9], login_statMsg[7], totalQuesMsg[5] = TOTAL_QUES;
totalQues = atoi(totalQuesMsg);
//for user
int userId;
//for wrongRecv
ssize_t send_ret,recv_ret;
//getting username and password
recv_ret = recv(new_fd,login_det,16,0);
if(recv_ret == 0)
{
return -2;
}
wrongRecv(recv_ret,16);
//extracting username nad password
strncpy(username,login_det,8);
strncpy(password,login_det+8,8);
username[8]='\0'; password[8]='\0';
//printf("username(%s) and password(%s)\n",username,password);
if( (userId = login(username,password)) > 0) {
//printf("%d\n",userId);
//sending status
strncpy(login_statMsg, LOGIN_OK, 2);
strncpy(login_statMsg + 2, totalQuesMsg , 5);
send_ret = send(new_fd, login_statMsg,7,0);
if(send_ret == 0)
{
return -2;
}
wrongRecv(send_ret,7);
//TODO error checking then handling if error
//users[userId][0] = 0; //score
users[userId][1] = new_fd; //file descriptor associated with this user
//users[userId][2] = 0; //answer time
return 1;
}
else if(userId == -1) { //wrong username
strncpy(login_statMsg, LOGIN_WrongUsername, 2);
strncpy(login_statMsg + 2, totalQuesMsg , 5);
send_ret = send(new_fd, login_statMsg,7,0);
if(send_ret == 0)
{
return -2;
}
wrongRecv(send_ret,7);
return 0;
}
else{
strncpy(login_statMsg, LOGIN_WrongPassword, 2);
strncpy(login_statMsg + 2, totalQuesMsg , 5);
send_ret = send(new_fd, login_statMsg,7,0);
if(send_ret == 0)
{
return -2;
}
wrongRecv(send_ret,7);
return 0;
}
//TODO erorr handling of above two case
//TODO make login a loop
}
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 listen_fd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr;//connection's address info
socklen_t sin_size;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;//IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if((rv = getaddrinfo(NULL,PORT, &hints, &servinfo)) != 0){ //getting which IPv server supports
fprintf(stderr, "getaddrinfo: %s\n",gai_strerror(rv));
return 1;
}
//loop through all the result and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next){
if((listen_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1){
perror("server : socket");
continue;
}
if(setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1){
perror("set sockopt");
exit(1);
}
if(bind(listen_fd, p->ai_addr, p->ai_addrlen) == -1){
close(listen_fd);
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(listen_fd, BACKLOG) == -1){
perror("listen");
exit(1);
}
//printf("listen_fd(%d)\n",listen_fd );
// 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");
fd_set master; //master file descriptor list
fd_set read_fds; //temp file descriptor list for select()
int fdmax;
FD_ZERO(&master); //clear the master and temp sets
FD_ZERO(&read_fds);
FD_SET(listen_fd, &master);
//keep track of the bigge file descriptor
fdmax = listen_fd; // so far it is this one
ssize_t recv_ret, send_ret;
//for login
int loginStatus;
struct sigaction sa;
sa.sa_handler = alarm_handler;
sigemptyset(&sa.sa_mask);
//sa.sa_flags = SA_RESTART;
if(sigaction(SIGALRM, &sa, NULL) == -1){
perror("sigaction");
exit(1);
}
//login while
alarm(LOGIN_WAIT);//accepting login only for 10 seconds
timer = 1;
printf("\n-----------------------------Waiting for users to login for %d seconds.-----------------------------\n",LOGIN_WAIT);
while(timer) {
sin_size = sizeof their_addr;
new_fd = accept(listen_fd, (struct sockaddr *)&their_addr, &sin_size);
if(new_fd == -1){
//perror("accept");
break;// this break is very important , as we are using alarm(Signals) and accept is a blocking function
//If accept is in blocked sate and our signal comes then accept will exit returning error. So
//if error then we have to break else next satements will run on falsy values.
//In reality we dont need this as I alredy set the SA_RESTART flag in sigaction which means
//after returning from the signal handler restart the activity on which you are previously
//instead of starting execution from next line.
}else {
inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s);
printf("server : got connection from %s\n", s);
//LOGIN //need to call login function via thread because this
//may stop the function if user doesnot respond
loginStatus = login_setup(new_fd);
//adding to select checkup
if(loginStatus) {
printf("User Loginned Succesfully\n");
}
}
}
printf("-----------------------------Login Closed. Now starting the QUIZ.-----------------------------\n");
//for randome seek
srand(time(NULL));
//for main loop counter
int i, win_fd;
//for questions
int QID = 0;
int maxQues_Len = 40, maxOpt_len = 10, maxQuesId_len = 5;//including '\0' this time
char quesMsg[80], answer[6];//score doesnot include \0
//char ques[40], optA[10], optB[10], optC[10], optD[10];
//for time calculation of each answer
ssize_t time_ques, time_ans;
//getting all avialable participants
fdmax = 0;
FD_ZERO(&master);
for(i = 0; i < MAX_USERS; i++) {
if( (new_fd = users[i][1]) != 0){
FD_SET(new_fd, &master);
if(new_fd > fdmax)
fdmax = new_fd;
//printf("%d\n",new_fd);
}
}
int current_rtt;
//while for main quiz
while(totalQues--) {
//checking who are ready for witing
if(select(fdmax+1, NULL, &master, NULL, NULL) == -1){//here select will return withh all the descriptors which are
//ready to write , all others have to miss this question
perror("select");
exit(1);
}
//setting which question to send
QID++;
//for sending questions to all
for(i = 0; i <= fdmax; i++) {
if(FD_ISSET(i, &master)) {
//rtt check
current_rtt = rtt_check(i);
if(current_rtt == -2) {//connection closed
FD_CLR(i, &master);
users_deleteFd(i);
continue;
}
//setting question
//nextQues(quesMsg, ques, optA, optB, optC, optD);
nextQues(quesMsg, QID);
printf("Sending Question QID(%s) fd(%d)\n",quesMsg,i);
//send a question
time_ques = time(NULL);
send_ret = send(i, quesMsg, maxQues_Len + 4 * maxOpt_len + maxQuesId_len, 0);
if(send_ret == 0) {//connection closed
FD_CLR(i, &master);
users_deleteFd(i);
continue;
}
wrongRecv(send_ret, maxQues_Len + 4 * maxOpt_len + maxQuesId_len);
}
}
//ASSUMING Question is send ot all the users at same time
//receiving and waiting for answers
alarm(MAX_ANSWER_TIME);
timer = 1;
FD_ZERO(&read_fds);
read_fds = master;
// unsigned int qq = read_fds.fd_count;
// for (int ii = 0; ii < qq; ++ii)
// {
// printf("%d\n",read_fds.fd_array[i] );
// }
while(timer) {
//printf("HURRAY\n");
if(select(fdmax+1, &read_fds, NULL, NULL, NULL) <=0){
perror("select");
//exit(4);
break;//break is important. Explained above
}
for(i = 0; i <= fdmax; i++) {
//printf("Recving answer I(%d)\n",i);
if(FD_ISSET(i, &read_fds)) {
//receiving answer
//TODO if we get answer to wrong ques
printf("Recving answer I(%d) fdmax (%d)\n",i,fdmax);
recv_ret = recv(i,answer,6,0);
time_ans = time(NULL);
wrongRecv(recv_ret,6);
printf("%s\n",answer );
if(recv_ret == 0)//connection closed
{
FD_CLR(i, &read_fds);
FD_CLR(i, &master);
users_deleteFd(i);
continue;
}else if(recv_ret > 0){
if(QID == atoi(answer)) { //we have received the answer to this question so remove the user from wait answer loop
FD_CLR(i, &read_fds);
//printf("%s i(%d)\n","#######",i );
answerCheck(i ,answer, current_rtt, (int) difftime(time_ans,time_ques));
//printf("Answer(%c)\n",answer[0]);
}
else{//we have recvd something unexpectable so ignore for NOW
}
}
//time_t cccc = time(NULL);
//printf("%s I(%d)\n",ctime(&cccc),i);
}
}
}
//comparing answers
win_fd = compareAnswer();
//sending score
}
return 0;
}
Client.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define PORT "3490" //the port client will be connecting to
#define MAXDATASIZE 100 // max number of bytes we can get at once
//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);
}
wrongRecv(ssize_t recvd, ssize_t expctd)
{
if(recvd != expctd)
{
printf("Recvd(%zd) bytes not equal to expected(%zd) bytes\n",recvd,expctd);
getchar();
}
}
void rtt_check(int sockfd)
{
ssize_t send_ret, recv_ret;
char rtt_check[1];
recv_ret = recv(sockfd, rtt_check, 1,0);
wrongRecv(recv_ret,1);
sleep(1);//to check
send_ret = send(sockfd, "r", 1, 0);
wrongRecv(send_ret, 1);
return;
}
int main(int argc, char *argv[])
{
int sockfd, numbytes;
char buf[MAXDATASIZE];
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
if(argc != 2) {
fprintf(stderr,"usage: client hostname\n");
exit(1);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) {
fprintf(stderr,"getaddrinfo: %s\n",gai_strerror(rv));
return 1;
}
//lopp through all the results and connect 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("client: socket");
continue;
}
if(connect(sockfd, p->ai_addr, p->ai_addrlen) == -1){
close(sockfd);
perror("client: connect");
continue;
}
break;
}
if(p ==NULL) {
fprintf(stderr,"client: failed to connect\n");
return 2;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), s, sizeof s);
printf("client : connecting to %s\n", s);
freeaddrinfo(servinfo); // all done with this structure
char login_det[17] = "abhishekabhishek";
char login_retMsg[7], login_stat[3], totalQuesMsg[5];
int totalQues;
//sending login details
ssize_t send_ret,recv_ret;
send_ret = send(sockfd, login_det,16,0);
wrongRecv(send_ret,16);
//receiving login status
recv_ret = recv(sockfd,login_retMsg,7,0);
wrongRecv(recv_ret,7);
strncpy(login_stat, login_retMsg, 2);
login_stat[2] = '\0';
printf("Login Status(%s)\n",login_stat);
strncpy(totalQuesMsg, login_retMsg + 2, 5);
totalQues = atoi(totalQuesMsg);
printf("totalQues(%d)\n",totalQues);
if(!strcmp(login_stat,"OK")) { //login ok
char quesId[5];
int maxQues_Len = 40, maxOpt_len = 10, maxQuesId_len = 5;//including '\0' this time
char quesMsg[80], scoreMsg[1];//score doesnot include \0
char ques[40], optA[10], optB[10], optC[10], optD[10];
char answer[6];
while(totalQues--) {
//checking rtt
rtt_check(sockfd);
//receving question
recv_ret = recv(sockfd, quesMsg, maxQues_Len + 4 * maxOpt_len + maxQuesId_len ,0);
wrongRecv(recv_ret, maxQues_Len + 4 * maxOpt_len + maxQuesId_len);
strncpy(quesId,quesMsg,5);
strncpy(ques, quesMsg + 05, 40);
strncpy(optA, quesMsg + 45, 10);
strncpy(optB, quesMsg + 55, 10);
strncpy(optC, quesMsg + 65, 10);
strncpy(optD, quesMsg + 75, 10);
printf("QUESID(%s) Question(%s), A(%s) , B(%s) , C(%s) , D(%s)\n", quesId, ques, optA, optB, optC, optD);
//choose answer
scoreMsg[0] = 'B';
strncpy(answer,quesId, 5);
answer[5] = scoreMsg[0];
sleep(5);
//sending answer
send_ret = send(sockfd, answer,6,0);
wrongRecv(send_ret,6);
printf("%s\n","Answer Message Sent" );
// if((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
// perror("recv");
// exit(1);
// }
// buf[numbytes] = '\0';
// printf("client: received '%s'\n",buf);
}
}
//TODO wrong login
close(sockfd);
return 0;
}
The problem is that the call to select in the answer getting loop is modifying read_fds to hold just the file descriptor of the first client(s) to respond. Since you don't reset read_fds before calling select again, it will not recognize the other clients' response.

Resources