LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 10-01-2011, 11:56 AM   #1
errigour
Member
 
Registered: May 2009
Posts: 366

Rep: Reputation: 6
Select doesn't seem to be working right.


I can't receive data from my client I was wondering if I
am calling FD_ISSET correctly or if there is something
that I am missing. Everything seems to work orderly but
FD_ISSET doesn't recognize that fact that I am sending
the server data.


Code:
struct descr *descr_list = NULL;
main
{
  for(;;)
    read_fds = master;
    write_fds = master;
    except_fds = master;
    select(fdmax+1, &read_fds, &write_fds, &except_fds, &seconds)
    newfd = accept(simpleSocket, (struct sockaddr *)&inco, &inclen);
    FD_SET(newfd, &master);
/*
I define a strucutre here then I add it to my descr_list
variable and it works, keepsake->newfd equals four
But FD_ISSET doesn't recognize that fact that I send
the server data.
*/
    struct descr *keepsake;
    keepsake = descr_list;
    while(keepsake != NULL)
    {
          /* This gets completly ignored */         
         if(FD_ISSET(keepsake->newfd, &read_fds))
         {
         	if(keepsake->state == CHARACTER_LOGIN)
                    character_login(keepsake);
    	        else if(keepsake->state==CREATE_CHARACTER)
                    create_character(keepsake);
         }
         /* This gets completly ignored */
         keepsake = keepsake->next;
    }
  }
}
 
Old 10-01-2011, 12:09 PM   #2
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Please post real code that will actually compile. I have no idea what you're passing to select, no idea what you're passing to FD_ISSET, and no idea what happens if FD_ISSET returns true.
Kevin Barry
 
Old 10-01-2011, 12:36 PM   #3
errigour
Member
 
Registered: May 2009
Posts: 366

Original Poster
Rep: Reputation: 6
I just hope this isn't to much to post

Code:
/**************************************************************************\
 * Type          * Bits*byte* Possible Values                             *
 **************************************************************************
 * short         * 16  *2   * -32768 to 65536                             *
 * unsigned short* 16  *2   * 0 to 65536                                  *
 *               *     *    *                                             *
 * int           * 32  *4   * -2147483648 to 4294967295                   *
 * long          * 32  *4   * -2147483648 to 4294967295                   *
 * unsigned int  * 32  *4   * 0 to 4294967295                             *
 * long long     * 64  *8   * -9223372036854778838 to 18446744073709551616*
 **************************************************************************
 * char      long      float     volatile                                 *
 * short     signed    double    void                                     *
 * int       unsigned  const                                              *
 *                                                                        *
 * char, signed char, unsigned char                                       *
 * int, signed int, unsigned int                                          *
 * short int, signed short int, unsigned short int                        *
 * long int, signed long int, unsigned long int                           *
 * float, double, long double                                             *
\**************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include "server.h"
#include "color.h"

/* Game state's, maximum allowed 65536 */
#define SAY_GOODBY          0 /* Character log off     */
#define CHARACTER_LOGIN     1 /* Character login       */
#define CREATE_CHARACTER    2 /* Character creation    */
#define CHARACTER_LOGGED_IN 3 /* Character is logged in*/

/* Game create_state's, maximum allowed 65536 */
#define CREATE_NAME       1 /* Tells create_character to check for the character's name     */
#define CREATE_PASSWORD   2 /* Tells create_character to check for the character's password */
#define VERIFY_PASSWORD   3 /* Tells create_character to verify the character's password    */
#define CHOOSE_SEX        4 /* Tells create_character to check for the character's sex      */
#define CHOOSE_RACE       5 /* Tells create_character to check for the character's race     */
#define CHOOSE_CLASS      6 /* Tells create_character to check for the character's class    */

struct descr *descr_list= NULL;

struct game_time
{
	int second;
	int minute;
	int hour;
	int day;
	int month;
	int year;
};

struct real_time
{
	int second;
	int minute;
	int hour;
	char day;
	char month;
	int year;
	int ampm;
};

struct descr
{
	int newfd;             /* Player socket                             */
	char char_name[11];    /* Character's name                          */
	char char_pass[25];    /* Character's password                      */
	short int sex;         /* Character's sex                           */
	short int char_class;  /* Characters class                          */
	short int char_race;   /* Characters race                           */
	short int state;       /* Game state                                */
	short int create_state;/* Character creation state                  */
	struct descr *next;    /* Used to create a linked list              */
	struct descr *list;    /* Used to define the top of the linked list */
};

int initialize_descr(int newfd, struct descr **p)
{
	struct descr *d;

	if(!(d = malloc(sizeof(struct descr))))
	{
		nonfatal("malloc failure initializing descr");
		return 0;
	}
	d->newfd = newfd;
	d->state = CHARACTER_LOGIN;
	d->next = NULL;
	d->list = descr_list;
	*p = d;

	if(descr_list == NULL)
	{
		descr_list = d;
		descr_list->list = descr_list;
	}
	else
	{
		while(descr_list->next != NULL)
		{
			descr_list=descr_list->next;
		}
		descr_list->next = d;
		descr_list->next->list = descr_list->list;
		descr_list = descr_list->list;
	}
	return 1;
}

int character_login(struct descr *d)
{
	int rbytes = 0;
	char buffer[12];
	const char er[] = "Character name must be less then, twelve characters.\r\n";
	const char ln[] = "Character name or (n)ew: ";
	
	if ((rbytes = recv(d->newfd, buffer, 12, 0)) <= 0)
	{
	    if (rbytes == 0)
		    printf("Socket %d hung up\n", d->newfd);
		else
		    nonfatal("Receiving a file descriptor");
		d->state=0;
		return -1;
	}
	else if (rbytes > 11)
	{
		send(d->newfd, er, sizeof er, 0);
		send(d->newfd, ln, sizeof ln, 0);
		return 0;
	}
	else
	{	
		if(buffer == "n" || buffer == "N")
		{
			send(d->newfd, "By what name do you wish to be known? ", 38, 0);
			d->state = CREATE_CHARACTER;   /* Now we know to Create a new character  */
			d->create_state = CREATE_NAME; /* Here we know to check for the username */
			return 1;
		}
		else
		{/*
			FILE *player = fopen(buffer,"r");
			if( player ) {
				d->state = ENTER_PASSWORD;  Enter character password
				fclose(fp);
			} 
			else
			{
				send(d->newfd, "Character does not exist", 24, 0);
			}*/
		}
	}
	return 1;
}

int create_character(struct descr *d)
{
	int rbytes = 0;
	char buffer[27];
	const char ne[] = "Character name must be less then, twelve characters.\r\n";
	const char nl[] = "By what name do you wish to be known? ";
	const char pe[] = "Password must be less then twenty six characters\r\n";
	const char pl[] = "Enter a password for you're character: ";
	const char vpe[]= "Passwords are not the same\r\n";
	const char vp[] = "Please varify you're password: ";
	const char se[] = "Please enter m , f or n\r\n";
	const char sl[] = "Please choose you're sex, \r\n(m)ale, (f)emale, or (n)one? ";
	const char race_menu[] = 
			   "Human\r\n"
			   "Drow\r\n"
			   "Barbarian\r\n"
			   "\r\n"
			   "Highlighted races are available: ";
	const char class_menu[] =
			   "(M)age\r\n"
			   "(W)arrior\r\n"
			   "(C)leric\r\n"
			   "(T)hief\r\n"
			   "\r\n"
			   "Highlighted classes are available: ";
	if ((rbytes = recv(d->newfd, buffer, 27, 0)) <= 0)
	{
	    if (rbytes == 0)
		    printf("Socket %d hung up\n", d->newfd);
		else
		    nonfatal("Receiving a file descriptor, function create_character");
		d->state=0;
		return -1;
	}
	if ( d->create_state == CREATE_NAME)
	{
		if (rbytes > 11)
		{
			send(d->newfd, ne, sizeof ne, 0);
			send(d->newfd, nl, sizeof nl, 0);
			return 0;
		}
		strcpy(d->char_name, buffer);
		d->create_state == CREATE_PASSWORD;
		send(d->newfd, pl, sizeof pl, 0);
	}
	else if (d->create_state == CREATE_PASSWORD)
	{
		if (rbytes > 25)
		{
			send(d->newfd, pe, sizeof pe, 0);
			send(d->newfd, pl, sizeof pl, 0);
			return 0;
		}
		strcpy (d->char_pass, buffer);
		d->create_state = VERIFY_PASSWORD;
		send(d->newfd, vp, sizeof vp, 0);
	}
	else if (d->create_state == VERIFY_PASSWORD)
	{
		if (rbytes > 25 || buffer != d->char_pass)
		{
			send(d->newfd, vpe, sizeof vpe, 0);
			send(d->newfd, pl, sizeof pl, 0);
			d->create_state = CREATE_PASSWORD;
			return 0;
		}
		strcpy(d->char_pass, buffer);
		d->create_state = CHOOSE_SEX;
		send(d->newfd, sl, sizeof sl, 0);
	}
	else if (d->create_state == CHOOSE_SEX)
	{
		if(buffer == "m" || buffer == "M"){d->sex = 0;}
		else if(buffer == "f" || buffer == "F"){d->sex = 1;}
		else if(buffer == "n" || buffer == "N"){d->sex = -1;}
		else
		{
			send(d->newfd, sl, sizeof sl, 0);
			return 0;
		}
		d->create_state = CHOOSE_RACE;
		send(d->newfd, race_menu, sizeof race_menu, 0);
	}
	else if (d->create_state == CHOOSE_RACE)
	{
		d->create_state = CHOOSE_CLASS;
		send(d->newfd, class_menu, sizeof class_menu, 0);
	}
	else if (d->create_state == CHOOSE_CLASS)
	{
		d->state = CHARACTER_LOGGED_IN;
		d->state = CREATE_CHARACTER;
		d->create_state = CREATE_NAME;
	}
}

int main()
{	
	struct sockaddr_in serv;
	struct sockaddr_in inco;
	struct game_time rtime;
	struct timeval seconds;
	socklen_t inclen;
	int simpleSocket;
	int yes = 1;
	int fdmax;        /* maximum file descriptor number */
	int newfd;
	unsigned int heart_pulse = 0;

	fd_set master;    /* master file descriptor list */
	fd_set read_fds;  /* will be watched to see if characters become available for reading */
	fd_set write_fds; /* will be watched to see if a write will not block */
	fd_set except_fds; /* will be watched for exceptions. */

	seconds.tv_sec  = 0;      /* seconds for select to wait for connections     */
	seconds.tv_usec = 1000;   /* microseconds for select to wait for connections
	                           * there are 1,000 microseconds in a millisecond
				               * there are 1,000 milliseconds in a second     
				               * thus there are 1,000,000 Microseconds in one 
				               * second, and there are 60 seconds in one minute */

	printf("Process id #%i\n", getpid());
	
	FD_ZERO(&master);    // clear the master and temp sets
	FD_ZERO(&read_fds);
	FD_ZERO(&write_fds);
	FD_ZERO(&except_fds);

	if ((simpleSocket=socket(AF_INET, SOCK_STREAM,0)) == -1)
	{
		fatal("Creating simpleSocket, AF_INET SOCK_STREAM failed");
	}
	fcntl(simpleSocket, F_SETFL, O_NONBLOCK); 
	setsockopt(simpleSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
  /*struct sockaddr_in
	{
		short   sin_family; must be AF_INET
		u_short sin_port;
		struct  in_addr sin_addr;
		char    sin_zero[8]; Not used, must be zero
	};
	struct in_addr { int s_addr; }; */
	serv.sin_family = AF_INET;
	serv.sin_addr.s_addr = INADDR_ANY;
	serv.sin_port = htons(2000);

	if (bind(simpleSocket,(struct sockaddr *)&serv,sizeof(serv)) == -1)
	{
		close(simpleSocket);
		fatal("Binding simpleSocket, AF_INET SOCK_STREAM failed");
	}

	if (listen(simpleSocket, 1000) == -1) 
	{
		close(simpleSocket);
		fatal("Listening to simpleSocket, AF_INET SOCK_STREAM failed");
    }

	// add the listener to the master set
    FD_SET(simpleSocket, &master);

    // keep track of the biggest file descriptor
    fdmax = simpleSocket; // so far, it's this one

	for(;;)
	{
		read_fds = master;
		write_fds = master;
		except_fds = master;

		/* Wait for connections for seconds amount of time and set the 
		   specific file descriptor for each connection */
		if (select(fdmax+1, &read_fds, &write_fds, &except_fds, &seconds) == -1)
            nonfatal("Select failed");
		/* handle new connections */
		if (FD_ISSET(simpleSocket, &read_fds))
		{
			/* Accept the next pending connection from simpleSocket */
			newfd = accept(simpleSocket, (struct sockaddr *)&inco, &inclen);
			if(newfd == -1)
				nonfatal("Accepting a file descriptor");
			else 
			{
				struct descr *init;
				FD_SET(newfd, &master); /* add to master set */
				if (newfd > fdmax)      /* keep track of the max */
                	fdmax = newfd;
    			const char name_prompt[] = "Character name or (n)ew: ";
    			const char error_prompt[]= "Unable to proceed please report this problem.";
    			if(initialize_descr(newfd, &init) == 0)
    			{
    				send(newfd, error_prompt, sizeof error_prompt, 0);
    				FD_CLR(newfd, &master);
    				close(newfd);
				}
    			else
    			{
    				send(init->newfd, name_prompt, sizeof name_prompt, 0);
					printf("New connection: on socket:  %d,\r\n", init->newfd);
					printf("                 sin_addr:  %s\r\n", inet_ntoa(inco.sin_addr));
				}
			}
		} /* END FD_ISSET(simpleSocket, &read_fds) */		
		
		heart_pulse++;
		if (heart_pulse == 15000) /* Longest int type unsigned long long int 18446744073709551616 */
		{
			if(rtime.second > -1)
				rtime.second++;
			if(rtime.second > 0x29) /* 41 */
			{
				rtime.second = 0x0; /* 0 */
				rtime.minute++;
				if(rtime.minute > 0x25) /* 37 */
				{
					rtime.minute = 0x0; /* 0 */
					rtime.hour++;
					if(rtime.hour > 0x15) /* 21 */
					{
						rtime.hour = 0x0; /* 0 */
						rtime.day++;
						if(rtime.day > 0x1b) /* 27 */
						{
							rtime.day = 0x1; /* 1 */
							rtime.month++;
							if(rtime.month > 0xA) /* 10 */
							{
								rtime.month = 0x1; /* 1 */
								rtime.year++;
								if(rtime.year > 0x17cf87f) /* 24967295 */
								{
									rtime.second = -1;
									rtime.minute = -1;
									rtime.hour = -1;
									rtime.day = -1;
									rtime.month = -1;
									rtime.year = -1; /* Apocolypse */
								}
							}
						}
					}
				}
			}
			
			int j;
			const char tick[] = "tick.";
			for(j = 0; j <= fdmax; j++) 
			{
				/* send to everyone! */
				if (FD_ISSET(j, &master)) 
				{
					send(j, tick, sizeof tick, 0);
				}
			}
			heart_pulse = 0;
		}
	    struct descr *keepsake, *r;
	    keepsake = descr_list;
    	while(keepsake != NULL)
    	{
     		if(FD_ISSET(keepsake->newfd, &read_fds))
     		{
	     		if(keepsake->state == CHARACTER_LOGIN)      /* Character login    */
		     		character_login(keepsake);
	     		else if(keepsake->state==CREATE_CHARACTER)  /* Character creation */
	     			create_character(keepsake);
     		}
     		keepsake = keepsake->next;
    	}
    	keepsake = descr_list;
    	while(descr_list != NULL)
    	{
	    	r = descr_list->next;
    	    if(descr_list->state == SAY_GOODBY)
     		{
	         	close(descr_list->newfd);
	         	FD_CLR(descr_list->newfd, &master);
         		free(descr_list);
     		}
     		descr_list = r;
 		}
 		descr_list = keepsake;
	}/* END for(;;).*/
    close(simpleSocket);
    exit(EXIT_SUCCESS);
}
 
Old 10-01-2011, 12:53 PM   #4
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Your indentation is inconsistent, making your code hard to follow. From what I can tell, though, you accept a new connection after select is called with only one descriptor (the bound socket), then you check the players' descriptors for input with FD_ISSET. This would be fine if descr_list wasn't cleared at the end of the for loop, which disconnects all users before select is called again. This means whenever select is called the only valid descriptor being watched is the bound socket.
Kevin Barry
 
Old 10-01-2011, 08:00 PM   #5
errigour
Member
 
Registered: May 2009
Posts: 366

Original Poster
Rep: Reputation: 6
are you sure that I am clearing descr_list and not setting descr_list to point to
the beginning of a linked list that I created? I thought I was only clearing
structures from descr_list that have a state variable equal to 0. Because
keepsake = a structure that points to the second structure on the list.

Is there anything you could suggest to do so that FD_ISSET will respond.
 
Old 10-01-2011, 08:35 PM   #6
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by errigour View Post
are you sure that I am clearing descr_list and not setting descr_list to point to
the beginning of a linked list that I created? I thought I was only clearing
structures from descr_list that have a state variable equal to 0. Because
keepsake = a structure that points to the second structure on the list.
You're probably correct here. I didn't take a look back at your initialization function and it looked like you accidentally placed an end-of-program cleanup loop inside the "for" loop.
Quote:
Originally Posted by errigour View Post
Is there anything you could suggest to do so that FD_ISSET will respond.
I don't know why I didn't realize this before, but you're providing write_fds to select and your sockets will always be ready for writing unless the clients aren't reading fast enough. That means write_fds will unblock select with all clients being ready for writing even when none are ready for reading. Use NULL instead of write_fds and except_fds. This might not be the fix since read_fds should eventually have something set, but it's a start. select probably doesn't ever block while clients are connected.

I'm not sure what happens with read_fds (etc.) when a timeout occurs. It could be that it's left unchanged, meaning that all descriptors will appear to be set if a timeout happens. This will give you a read error in recv, making it appear that the client is disconnected. seconds also gets overwritten by select in Linux with the timeout left, so if the timeout expires (I think) seconds will be set to equal zero, making select stop blocking. You should both reset seconds every loop and continue if the return of select is 0.
Kevin Barry

Last edited by ta0kira; 10-01-2011 at 08:57 PM.
 
Old 10-02-2011, 12:03 PM   #7
errigour
Member
 
Registered: May 2009
Posts: 366

Original Poster
Rep: Reputation: 6
Yea I can't seem to get it to work.

Also I wanted to post these because I forgot they where included.

Code:
void fatal(const char *message) {
   char error_message[100];


   strcpy(error_message, "[!!] Fatal Error : ");
   strncat(error_message, message, 83);
   perror(error_message);
   exit(EXIT_FAILURE);
}
void nonfatal(const char *message) {
	char error_message[100];


	strcpy(error_message, "[!!] Non Fatal Error : ");
	strncat(error_message, message, 83);
	perror(error_message);
}

Last edited by errigour; 10-02-2011 at 12:12 PM.
 
Old 10-02-2011, 01:14 PM   #8
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by errigour View Post
Yea I can't seem to get it to work.
So it still doesn't work after the three suggestions I made (get rid of write_fds and except_fds, reset seconds each time around, and continue when select returns 0)? Try printing out the FD_ISSET value for all client descriptors in read_fds before and after the select call, as well as the return value of select. That will at least tell you if they're set correctly in the first place. Also, is FD_ISSET just not returning "true" or is it returning "true" but there isn't anything there to recv?
Kevin Barry
 
Old 10-02-2011, 03:51 PM   #9
errigour
Member
 
Registered: May 2009
Posts: 366

Original Poster
Rep: Reputation: 6
No it's just not returning true. I know because I put a
printf statement in the brackets of the if statement so
it skips it completly. FD_ISSET(j, &master) works and it even
works as FD_ISSET(keepsake->newfd, &master but not the read_fd
statement.
 
Old 10-02-2011, 03:56 PM   #10
errigour
Member
 
Registered: May 2009
Posts: 366

Original Poster
Rep: Reputation: 6
Yea I tried all three together and individually.
 
Old 10-02-2011, 04:11 PM   #11
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by errigour View Post
No it's just not returning true. I know because I put a
printf statement in the brackets of the if statement so
it skips it completly. FD_ISSET(j, &master) works and it even
works as FD_ISSET(keepsake->newfd, &master but not the read_fd
statement.
This is because you set it in master and you didn't pass master to select; select is what unsets the descriptors that aren't ready. fd_set is just a set of bits indicating whether or not to watch the descriptors corresponding to the bits (before select) or if those descriptors are ready (after select). I'm going to assume that you're still using write_fds since you haven't acknowledged that I suggested using NULL instead. In addition to all client sockets always being ready for writing, the bound socket isn't a valid "write" location. select doesn't have to return all ready file descriptors; it just needs to return one that's ready. This means select can return with write_fds having only one bit set and since you never deal with that condition it can keep returning with the same result over and over again, never returning with anything in read_fds set (except when no clients are connected; the bound socket will be ready for reading when accept won't block and it won't ever be ready for writing.)

As a side comment, you should also block SIGPIPE since it's possible you might write to a socket that's closed on the other end. If you don't block or handle it the write will terminate your server program.
Kevin Barry
 
Old 10-02-2011, 04:12 PM   #12
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by errigour View Post
Yea I tried all three together and individually.
Sorry, you posted this while I was working on my other post. So what, if anything, is set in read_fds after select? What is the return of select?
Kevin Barry
 
Old 10-02-2011, 04:37 PM   #13
errigour
Member
 
Registered: May 2009
Posts: 366

Original Poster
Rep: Reputation: 6
Can you show me a easy small fix?
I am a bit lost but an example would help
you don't have to post the whole server
the the parts of the code that you chang
I mean if would help me.

Also FD_ISSET(simplesocket, &read_fds) doesn't get ignored
only when I check read_fdslater in the program.
 
Old 10-02-2011, 05:53 PM   #14
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by errigour View Post
Can you show me a easy small fix?
I am a bit lost but an example would help
you don't have to post the whole server
the the parts of the code that you chang
I mean if would help me.

Also FD_ISSET(simplesocket, &read_fds) doesn't get ignored
only when I check read_fdslater in the program.
Outwardly it appears you're doing it correctly (provided you made and kept the changes I suggested), which is why I'm asking you to check the values of various things throughout the loop. Please post your current code with the changes I suggested so I can see it all in one place. Thanks!
Kevin Barry
 
Old 10-03-2011, 06:34 AM   #15
errigour
Member
 
Registered: May 2009
Posts: 366

Original Poster
Rep: Reputation: 6
Alright this has the changes
Code:
/**************************************************************************\
 * Type          * Bits*byte* Possible Values                             *
 **************************************************************************
 * short         * 16  *2   * -32768 to 65536                             *
 * unsigned short* 16  *2   * 0 to 65536                                  *
 *               *     *    *                                             *
 * int           * 32  *4   * -2147483648 to 4294967295                   *
 * long          * 32  *4   * -2147483648 to 4294967295                   *
 * unsigned int  * 32  *4   * 0 to 4294967295                             *
 * long long     * 64  *8   * -9223372036854778838 to 18446744073709551616*
 **************************************************************************
 * char      long      float     volatile                                 *
 * short     signed    double    void                                     *
 * int       unsigned  const                                              *
 *                                                                        *
 * char, signed char, unsigned char                                       *
 * int, signed int, unsigned int                                          *
 * short int, signed short int, unsigned short int                        *
 * long int, signed long int, unsigned long int                           *
 * float, double, long double                                             *
\**************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include "color.h"

/* Game state's, maximum allowed 65536 */
#define SAY_GOODBY          0 /* Character log off     */
#define CHARACTER_LOGIN     1 /* Character login       */
#define CREATE_CHARACTER    2 /* Character creation    */
#define CHARACTER_LOGGED_IN 3 /* Character is logged in*/

/* Game create_state's, maximum allowed 65536 */
#define CREATE_NAME       1 /* Tells create_character to check for the character's name     */
#define CREATE_PASSWORD   2 /* Tells create_character to check for the character's password */
#define VERIFY_PASSWORD   3 /* Tells create_character to verify the character's password    */
#define CHOOSE_SEX        4 /* Tells create_character to check for the character's sex      */
#define CHOOSE_RACE       5 /* Tells create_character to check for the character's race     */
#define CHOOSE_CLASS      6 /* Tells create_character to check for the character's class    */

struct descr *descr_list= NULL;

struct game_time
{
	int second;
	int minute;
	int hour;
	int day;
	int month;
	int year;
};

struct real_time
{
	int second;
	int minute;
	int hour;
	char day;
	char month;
	int year;
	int ampm;
};

struct descr
{
	int newfd;             /* Player socket                             */
	char char_name[11];    /* Character's name                          */
	char char_pass[25];    /* Character's password                      */
	short int sex;         /* Character's sex                           */
	short int char_class;  /* Characters class                          */
	short int char_race;   /* Characters race                           */
	short int state;       /* Game state                                */
	short int create_state;/* Character creation state                  */
	struct descr *next;    /* Used to create a linked list              */
	struct descr *list;    /* Used to define the top of the linked list */
};

void fatal(const char *message) {
   char error_message[100];


   strcpy(error_message, "[!!] Fatal Error : ");
   strncat(error_message, message, 83);
   perror(error_message);
   exit(EXIT_FAILURE);
}
void nonfatal(const char *message) {
	char error_message[100];


	strcpy(error_message, "[!!] Non Fatal Error : ");
	strncat(error_message, message, 83);
	perror(error_message);
}

int initialize_descr(int newfd, struct descr **p)
{
	struct descr *d;

	if(!(d = malloc(sizeof(struct descr))))
	{
		nonfatal("malloc failure initializing descr");
		return 0;
	}
	d->newfd = newfd;
	d->state = CHARACTER_LOGIN;
	d->next = NULL;
	d->list = descr_list;
	*p = d;

	if(descr_list == NULL)
	{
		descr_list = d;
		descr_list->list = descr_list;
	}
	else
	{
		while(descr_list->next != NULL)
		{
			descr_list=descr_list->next;
		}
		descr_list->next = d;
		descr_list->next->list = descr_list->list;
		descr_list = descr_list->list;
	}
	return 1;
}

int character_login(struct descr *d)
{
	int rbytes = 0;
	char buffer[12];
	const char er[] = "Character name must be less then, twelve characters.\r\n";
	const char ln[] = "Character name or (n)ew: ";
	
	if ((rbytes = recv(d->newfd, buffer, 12, 0)) <= 0)
	{
	    if (rbytes == 0)
		    printf("Socket %d hung up\n", d->newfd);
		else
		    nonfatal("Receiving a file descriptor");
		d->state=0;
		return -1;
	}
	else if (rbytes > 11)
	{
		send(d->newfd, er, sizeof er, 0);
		send(d->newfd, ln, sizeof ln, 0);
		return 0;
	}
	else
	{	
		if(buffer == "n" || buffer == "N")
		{
			send(d->newfd, "By what name do you wish to be known? ", 38, 0);
			d->state = CREATE_CHARACTER;   /* Now we know to Create a new character  */
			d->create_state = CREATE_NAME; /* Here we know to check for the username */
			return 1;
		}
		else
		{/*
			FILE *player = fopen(buffer,"r");
			if( player ) {
				d->state = ENTER_PASSWORD;  Enter character password
				fclose(fp);
			} 
			else
			{
				send(d->newfd, "Character does not exist", 24, 0);
			}*/
		}
	}
	return 1;
}

int create_character(struct descr *d)
{
	int rbytes = 0;
	char buffer[27];
	const char ne[] = "Character name must be less then, twelve characters.\r\n";
	const char nl[] = "By what name do you wish to be known? ";
	const char pe[] = "Password must be less then twenty six characters\r\n";
	const char pl[] = "Enter a password for you're character: ";
	const char vpe[]= "Passwords are not the same\r\n";
	const char vp[] = "Please varify you're password: ";
	const char se[] = "Please enter m , f or n\r\n";
	const char sl[] = "Please choose you're sex, \r\n(m)ale, (f)emale, or (n)one? ";
	const char race_menu[] = 
			   "Human\r\n"
			   "Drow\r\n"
			   "Barbarian\r\n"
			   "\r\n"
			   "Highlighted races are available: ";
	const char class_menu[] =
			   "(M)age\r\n"
			   "(W)arrior\r\n"
			   "(C)leric\r\n"
			   "(T)hief\r\n"
			   "\r\n"
			   "Highlighted classes are available: ";
	if ((rbytes = recv(d->newfd, buffer, 27, 0)) <= 0)
	{
	    if (rbytes == 0)
		    printf("Socket %d hung up\n", d->newfd);
		else
		    nonfatal("Receiving a file descriptor, function create_character");
		d->state=0;
		return -1;
	}
	if ( d->create_state == CREATE_NAME)
	{
		if (rbytes > 11)
		{
			send(d->newfd, ne, sizeof ne, 0);
			send(d->newfd, nl, sizeof nl, 0);
			return 0;
		}
		strcpy(d->char_name, buffer);
		d->create_state == CREATE_PASSWORD;
		send(d->newfd, pl, sizeof pl, 0);
	}
	else if (d->create_state == CREATE_PASSWORD)
	{
		if (rbytes > 25)
		{
			send(d->newfd, pe, sizeof pe, 0);
			send(d->newfd, pl, sizeof pl, 0);
			return 0;
		}
		strcpy (d->char_pass, buffer);
		d->create_state = VERIFY_PASSWORD;
		send(d->newfd, vp, sizeof vp, 0);
	}
	else if (d->create_state == VERIFY_PASSWORD)
	{
		if (rbytes > 25 || buffer != d->char_pass)
		{
			send(d->newfd, vpe, sizeof vpe, 0);
			send(d->newfd, pl, sizeof pl, 0);
			d->create_state = CREATE_PASSWORD;
			return 0;
		}
		strcpy(d->char_pass, buffer);
		d->create_state = CHOOSE_SEX;
		send(d->newfd, sl, sizeof sl, 0);
	}
	else if (d->create_state == CHOOSE_SEX)
	{
		if(buffer == "m" || buffer == "M"){d->sex = 0;}
		else if(buffer == "f" || buffer == "F"){d->sex = 1;}
		else if(buffer == "n" || buffer == "N"){d->sex = -1;}
		else
		{
			send(d->newfd, se, sizeof se, 0);
			send(d->newfd, sl, sizeof sl, 0);
			return 0;
		}
		d->create_state = CHOOSE_RACE;
		send(d->newfd, race_menu, sizeof race_menu, 0);
	}
	else if (d->create_state == CHOOSE_RACE)
	{
		d->create_state = CHOOSE_CLASS;
		send(d->newfd, class_menu, sizeof class_menu, 0);
	}
	else if (d->create_state == CHOOSE_CLASS)
	{
		d->state = CHARACTER_LOGGED_IN;
		d->state = CREATE_CHARACTER;
		d->create_state = CREATE_NAME;
	}
}

int main()
{	
	struct sockaddr_in serv;
	struct sockaddr_in inco;
	struct game_time rtime;
	struct timeval seconds;
	socklen_t inclen;
	int simpleSocket;
	int yes = 1;
	int fdmax;        /* maximum file descriptor number */
	int newfd;
	unsigned int heart_pulse = 0;

	fd_set master;    /* master file descriptor list */
	fd_set read_fds;  /* will be watched to see if characters become available for reading */
	fd_set write_fds; /* will be watched to see if a write will not block */
	fd_set except_fds; /* will be watched for exceptions. */

	seconds.tv_sec  = 0;      /* seconds for select to wait for connections     */
	seconds.tv_usec = 1000;   /* microseconds for select to wait for connections
	                           * there are 1,000 microseconds in a millisecond
				               * there are 1,000 milliseconds in a second     
				               * thus there are 1,000,000 Microseconds in one 
				               * second, and there are 60 seconds in one minute */

	printf("Process id #%i\n", getpid());
	
	FD_ZERO(&master);    // clear the master and temp sets
	FD_ZERO(&read_fds);
	FD_ZERO(&write_fds);
	FD_ZERO(&except_fds);

	if ((simpleSocket=socket(AF_INET, SOCK_STREAM,0)) == -1)
	{
		fatal("Creating simpleSocket, AF_INET SOCK_STREAM failed");
	}
	fcntl(simpleSocket, F_SETFL, O_NONBLOCK); 
	setsockopt(simpleSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
  /*struct sockaddr_in
	{
		short   sin_family; must be AF_INET
		u_short sin_port;
		struct  in_addr sin_addr;
		char    sin_zero[8]; Not used, must be zero
	};
	struct in_addr { int s_addr; }; */
	serv.sin_family = AF_INET;
	serv.sin_addr.s_addr = INADDR_ANY;
	serv.sin_port = htons(2000);

	if (bind(simpleSocket,(struct sockaddr *)&serv,sizeof(serv)) == -1)
	{
		close(simpleSocket);
		fatal("Binding simpleSocket, AF_INET SOCK_STREAM failed");
	}

	if (listen(simpleSocket, 1000) == -1) 
	{
		close(simpleSocket);
		fatal("Listening to simpleSocket, AF_INET SOCK_STREAM failed");
    }

	// add the listener to the master set
    FD_SET(simpleSocket, &master);

    // keep track of the biggest file descriptor
    fdmax = simpleSocket; // so far, it's this one

	for(;;)
	{
		struct descr *keepsake, *r;

	seconds.tv_sec  = 0;      /* seconds for select to wait for connections     */
	seconds.tv_usec = 1000;   /* microseconds for select to wait for connections
	                           * there are 1,000 microseconds in a millisecond
				               * there are 1,000 milliseconds in a second     
				               * thus there are 1,000,000 Microseconds in one 
				               * second, and there are 60 seconds in one minute */
		read_fds = master;
		//write_fds = master;
		//except_fds = master;

		/* Wait for connections for seconds amount of time and set the 
		   specific file descriptor for each connection */
		//if (select(fdmax+1, &read_fds, &write_fds, &except_fds, &seconds) == -1)
          //  nonfatal("Select failed");
          if(select(fdmax+1, &read_fds, NULL, NULL, &seconds) == 0)
          	continue;

		/* handle new connections */
		if (FD_ISSET(simpleSocket, &read_fds))
		{
			/* Accept the next pending connection from simpleSocket */
			newfd = accept(simpleSocket, (struct sockaddr *)&inco, &inclen);
			if(newfd == -1)
				nonfatal("Accepting a file descriptor");
			else 
			{
				struct descr *init;
				FD_SET(newfd, &master);   /* add to master set */
				if (newfd > fdmax)        /* keep track of the max */
                	fdmax = newfd;
    			const char name_prompt[] = "Character name or (n)ew: ";
    			const char error_prompt[]= "Unable to proceed please report this problem.";
    			if(initialize_descr(newfd, &init) == 0)
    			{
    				send(newfd, error_prompt, sizeof error_prompt, 0);
    				FD_CLR(newfd, &master);
    				close(newfd);
				}
    			else
    			{
    				send(init->newfd, name_prompt, sizeof name_prompt, 0);
					printf("New connection: on socket:  %d,\r\n", init->newfd);
					printf("                 sin_addr:  %s\r\n", inet_ntoa(inco.sin_addr));
				}
			}
		} /* END FD_ISSET(simpleSocket, &read_fds) */
		
		heart_pulse++;
		if (heart_pulse == 15000) /* Longest int type unsigned long long int 18446744073709551616 */
		{
			if(rtime.second > -1)
				rtime.second++;
			if(rtime.second > 0x29) /* 41 */
			{
				rtime.second = 0x0; /* 0 */
				rtime.minute++;
				if(rtime.minute > 0x25) /* 37 */
				{
					rtime.minute = 0x0; /* 0 */
					rtime.hour++;
					if(rtime.hour > 0x15) /* 21 */
					{
						rtime.hour = 0x0; /* 0 */
						rtime.day++;
						if(rtime.day > 0x1b) /* 27 */
						{
							rtime.day = 0x1; /* 1 */
							rtime.month++;
							if(rtime.month > 0xA) /* 10 */
							{
								rtime.month = 0x1; /* 1 */
								rtime.year++;
								if(rtime.year > 0x17cf87f) /* 24967295 */
								{
									rtime.second = -1;
									rtime.minute = -1;
									rtime.hour = -1;
									rtime.day = -1;
									rtime.month = -1;
									rtime.year = -1; /* Apocolypse */
								}
							}
						}
					}
				}
			}
			
			int j;
			const char tick[] = "tick.";
			for(j = 0; j <= fdmax; j++) 
			{
				/* send to everyone! */
				if (FD_ISSET(j, &master)) 
				{
					send(j, tick, sizeof tick, 0);
				}
			}
			heart_pulse = 0;
		}

	    keepsake = descr_list;
    	while(keepsake != NULL)
    	{
	    	if(FD_ISSET(keepsake->newfd, &read_fds))
     		{
		   		if(keepsake->state == CHARACTER_LOGIN)      /* Character login    */
		   			character_login(keepsake);
	    		else if(keepsake->state==CREATE_CHARACTER)  /* Character creation */
		   			create_character(keepsake);
     		}
     		keepsake = keepsake->next;
		}
    	keepsake = descr_list;
    	while(descr_list != NULL)
    	{
	    	r = descr_list->next;
    	    if(descr_list->state == SAY_GOODBY)
     		{
	         	close(descr_list->newfd);
	         	FD_CLR(descr_list->newfd, &master);
         		free(descr_list);
     		}
     		descr_list = r;
 		}
 		descr_list = keepsake;
	}/* END for(;;).*/
    close(simpleSocket);
    exit(EXIT_SUCCESS);
}
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
fprintf() before select() doesn't print anything exponential Programming 2 04-23-2007 01:05 PM
MySQL the syntax to SELECT doesn't work for DELETE Melsync Programming 2 03-31-2007 05:59 AM
DVD menu - doesn't work/can't select anything pingu Linux - Software 3 10-31-2005 09:33 AM
Using Select to make a simple directory menu why doesn't it work ctrimble Programming 5 06-07-2004 01:21 AM
Cut(Select) and Paste doesn't work! andykerouac Linux - General 0 02-11-2004 02:32 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 06:23 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration