Pirates Pirates - 24 days ago 7
C Question

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.

Answer

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.