Code:
#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"
/* Game create_state's, maximum allowed 65536 */
#define PERGITORY 0 /* Tells create_character to announce there pergitory position */
#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 */
#define NUM_CREATE_STATES 7 /* The number of creation states */
/* 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 */
#define NUM_GAME_STATES 4 /* The number of game states */
/* Gender types */
#define GENDER_NEUTRAL 0 /* The gender type neutral */
#define GENDER_MALE 1 /* The gender type male */
#define GENDER_FEMALE 2 /* The gender type female */
#define NUM_GENDERS 3 /* The number of genders */
struct descr *descr_list = NULL;
/* Game time */
struct game_time
{
short int second; /* Game time seconds */
short int minute; /* Game time minutes */
short int hour; /* Game time hours */
short int day; /* Game time days */
short int month; /* Game time months */
short int year; /* Game time years */
};
/* Real time */
struct real_time
{
short int second; /* Real time seconds */
short int minute; /* Real time minutes */
short int hour; /* Real time hours */
short int day; /* Real time days */
short int month; /* Real time months */
short int year; /* Real time years */
};
struct descr
{
int newfd; /* Player socket */
char char_name[11]; /* Character's name */
char char_pass[27]; /* 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;
}
else
{
while(descr_list->next != NULL)
{
descr_list=descr_list->next;
}
descr_list->next = d;
descr_list = descr_list->list;
}
return 1;
}
/*************************************************************************************
* This is a character login function created for a passive style multi user dungeon *
* game. It returns -1 if it receives less then or equal to zero bytes. It returns *
* 0 if it receives stuff over the control limits of the integers. It returns 1 if *
* everything is acceptable and the state has been changed. Lastly if the function *
* reaches the the last return then it will return -2 which should never be reached *
* by the program *
*************************************************************************************/
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 err[]= "Please enter either (n) or (N).\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=SAY_GOODBY;
return -1;
}
else if (rbytes > 13)
{
send(d->newfd, er, sizeof er, 0);
send(d->newfd, ln, sizeof ln, 0);
return 0;
}
else
{
if (rbytes == 3)
{
if((buffer[0] == 'n' || buffer[0] == 'N'))
{
d->state = CREATE_CHARACTER; /* Now we know to Create a new character */
d->create_state = CREATE_NAME; /* Here we know to create the username */
send(d->newfd, "By what name do you wish to be known? ", 38, 0);
return 1;
}
else
{
send(d->newfd, err, sizeof err, 0);
send(d->newfd, ln, sizeof ln, 0);
return 0;
}
}
else
{
send(d->newfd, err, sizeof err, 0);
send(d->newfd, ln, sizeof ln, 0);
return 0;
}
/*
int *fp;
FILE *fp = fopen(buffer, "r");
if( fp )
{
d->state = ENTER_PASSWORD; Enter character password
fclose(fp);
return 1;
}
else
{
send(d->newfd, "Character does not exist", 24, 0);
return 0;
}*/
}
return -2;
}
/************************************************************************************
*This is a character creation script used for prompting players to select aspects *
*of a character sheet for there personal use as they play this multi user dungeon *
*game. It returns -1 if recv returns less then or equal to 0. It returns 0 if a *
*player enters an amount of data that is larger then the integer that is waiting *
*to recieve it. It returns 1 if the player has entered a validated option and this *
*function will return -2 if it recheas it's end which should never happen. *
************************************************************************************/
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 eight characters.\r\n";
const char pl[] = "Please 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 or type (b)ack: ";
const char se[] = "Please enter (m)ale , (f)emale or (n)eutral.\r\n";
const char sl[] = "Please choose you're sex, \r\n(m)ale, (f)emale, or (n)eutral? ";
const char race_menu[] =
"(H)uman\r\n"
"(D)row\r\n"
"(B)arbarian\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=SAY_GOODBY;
return -1;
}
if ( d->create_state == CREATE_NAME)
{
if (rbytes > 13)
{
send(d->newfd, ne, sizeof ne, 0);
send(d->newfd, nl, sizeof nl, 0);
return 0;
}
else
{
strncpy(d->char_name, buffer, rbytes - 2);
d->create_state = CREATE_PASSWORD;
send(d->newfd, pl, sizeof pl, 0);
return 1;
}
}
else if (d->create_state == CREATE_PASSWORD)
{
if (rbytes > 29)
{
send(d->newfd, pe, sizeof pe, 0);
send(d->newfd, pl, sizeof pl, 0);
return 0;
}
else
{
strncpy(d->char_pass, buffer, rbytes - 2);
d->create_state = VERIFY_PASSWORD;
send(d->newfd, vp, sizeof vp, 0);
return 1;
}
}
else if (d->create_state == VERIFY_PASSWORD)
{
char tmp[27];
if (rbytes < 30)
strncpy(tmp, buffer, rbytes - 2);
if (rbytes == 3 && (buffer[0] == 'b' || buffer[0] == 'B'))
{
d->create_state = CREATE_PASSWORD;
send(d->newfd, pe, sizeof pe, 0);
send(d->newfd, pl, sizeof pl, 0);
return 1;
}
else if (rbytes > 29 || (strncmp(tmp, d->char_pass, rbytes -2) != 0))
{
send(d->newfd, vpe, sizeof vpe, 0);
send(d->newfd, vp, sizeof vp, 0);
return 0;
}
else
{
d->create_state = CHOOSE_SEX;
send(d->newfd, sl, sizeof sl, 0);
return 1;
}
}
else if (d->create_state == CHOOSE_SEX)
{
if (rbytes > 3) {
send(d->newfd, se, sizeof se, 0);
send(d->newfd, sl, sizeof sl, 0);
return 0;
}
else
{
if(buffer[0] == 'n' || buffer[0] == 'N'){d->sex = GENDER_NEUTRAL;}
else if(buffer[0] == 'M' || buffer[0] == 'M'){d->sex = GENDER_MALE;}
else if(buffer[0] == 'F' || buffer[0] == 'F'){d->sex = GENDER_FEMALE;}
d->create_state = CHOOSE_RACE;
send(d->newfd, race_menu, sizeof race_menu, 0);
return 1;
}
}
else if (d->create_state == CHOOSE_RACE)
{
d->create_state = CHOOSE_CLASS;
send(d->newfd, class_menu, sizeof class_menu, 0);
return 1;
}
else if (d->create_state == CHOOSE_CLASS)
{
d->state = CHARACTER_LOGGED_IN;
d->state = CREATE_CHARACTER;
d->create_state = CREATE_NAME;
return 1;
}
return -2;
}
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));
serv.sin_family = AF_INET;
serv.sin_addr.s_addr = INADDR_ANY;
serv.sin_port = htons(4000);
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, *tmp;
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) /* The longest int type is 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; /* Apocolypse */
rtime.minute = -1; /* Apocolypse */
rtime.hour = -1; /* Apocolypse */
rtime.day = -1; /* Apocolypse */
rtime.month = -1; /* Apocolypse */
rtime.year = -1; /* Apocolypse */
}/* END if(rtime.year > 0x17cf87f) */
}/* END if(rtime.month > 0xA) */
}/* END if(rtime.day > 0x1b) */
}/* END if(rtime.hour > 0x15) */
}/* END if(rtime.minute > 0x25) */
}/* END if(rtime.second > 0x29) */
int j;
const char tick[5] = "tick.";
for(j = 0; j <= fdmax; j++)
{
/* send to everyone! */
if (FD_ISSET(j, &master))
{
//send(j, tick, sizeof tick, 0);
}
}
heart_pulse = 0;
} /* END if (heart_pulse == 15000) */
keepsake = descr_list;
while(descr_list != NULL)
{
if(FD_ISSET(descr_list->newfd, &read_fds))
{
if(descr_list->state == CHARACTER_LOGIN) /* Character login */
{
character_login(descr_list);
}
else if(descr_list->state == CREATE_CHARACTER) /* Character creation */
{
create_character(descr_list);
}
}
descr_list = descr_list->next;
}
descr_list = keepsake;
if(descr_list)
{
while(descr_list->state == SAY_GOODBY && descr_list->next != NULL)
{
descr_list = descr_list->next;
}
tmp = keepsake;
keepsake = descr_list;
descr_list = tmp;
}
while(descr_list != NULL)
{
tmp = descr_list->next;
if(descr_list->state == SAY_GOODBY)
{
close(descr_list->newfd);
FD_CLR(descr_list->newfd, &master);
free(descr_list);
}
descr_list = tmp;
}
descr_list = keepsake;
}/* END for(;;) */
close(simpleSocket);
exit(EXIT_SUCCESS);
}