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
Welcome to
LinuxQuestions.org , a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free.
Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please
contact us . If you need to reset your password,
click here .
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a
virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month.
Click here for more info.
10-01-2011, 11:56 AM
#1
Member
Registered: May 2009
Posts: 366
Rep:
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;
}
}
}
10-01-2011, 12:09 PM
#2
Senior Member
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078
Rep:
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
10-01-2011, 12:36 PM
#3
Member
Registered: May 2009
Posts: 366
Original Poster
Rep:
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);
}
10-01-2011, 12:53 PM
#4
Senior Member
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078
Rep:
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
10-01-2011, 08:00 PM
#5
Member
Registered: May 2009
Posts: 366
Original Poster
Rep:
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.
10-01-2011, 08:35 PM
#6
Senior Member
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078
Rep:
Quote:
Originally Posted by
errigour
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
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 .
10-02-2011, 12:03 PM
#7
Member
Registered: May 2009
Posts: 366
Original Poster
Rep:
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 .
10-02-2011, 01:14 PM
#8
Senior Member
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078
Rep:
Quote:
Originally Posted by
errigour
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
10-02-2011, 03:51 PM
#9
Member
Registered: May 2009
Posts: 366
Original Poster
Rep:
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.
10-02-2011, 03:56 PM
#10
Member
Registered: May 2009
Posts: 366
Original Poster
Rep:
Yea I tried all three together and individually.
10-02-2011, 04:11 PM
#11
Senior Member
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078
Rep:
Quote:
Originally Posted by
errigour
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
10-02-2011, 04:12 PM
#12
Senior Member
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078
Rep:
Quote:
Originally Posted by
errigour
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
10-02-2011, 04:37 PM
#13
Member
Registered: May 2009
Posts: 366
Original Poster
Rep:
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.
10-02-2011, 05:53 PM
#14
Senior Member
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078
Rep:
Quote:
Originally Posted by
errigour
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
10-03-2011, 06:34 AM
#15
Member
Registered: May 2009
Posts: 366
Original Poster
Rep:
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);
}
All times are GMT -5. The time now is 06:23 PM .
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know .
Latest Threads
LQ News