/*
* socket.c - routines to handle all socket matters for Phantasia
*/
#include "include.h"
extern void *Do_start_thread(void *c);
extern server_hook;
extern randData;
/************************************************************************
/
/ FUNCTION NAME: Do_initialize_socket(struct server_t *server)
/
/ FUNCTION: To initialize the program's socket
/
/ AUTHOR: Brian Kelly, 4/12/99
/
/ ARGUMENTS:
/ struct server_t *s - address of the server's main data strcture
/
/ RETURN VALUE:
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/ This routine is specially designed to:
/
/ - strip non-printing characters (unless Wizard)
/ - echo, if desired
/ - redraw the screen if CH_REDRAW is entered
/ - read in only 'mx - 1' characters or less characters
/ - nul-terminate string, and throw away newline
/
/ 'mx' is assumed to be at least 2.
/
*************************************************************************/
int Do_init_server_socket()
{
struct sockaddr_in bind_address;
char error_msg[SZ_ERROR_MESSAGE];
int the_socket, error, on=1;
/* create a socket */
errno = 0;
if ((the_socket=socket(AF_INET, SOCK_STREAM, 0)) == -1) {
sprintf(error_msg,
"[0.0.0.0:?] Socket creation failed in Do_init_server_socket: %s\n",
strerror(errno));
Do_log_error(error_msg);
exit(SOCKET_CREATE_ERROR);
}
error = setsockopt(the_socket, SOL_SOCKET, SO_REUSEADDR,
(char *) &on, sizeof(on));
if (error != 0) {
sprintf(error_msg, "[0.0.0.0:?] setsockopt failed with error code of %d in Do_init_server_socket.\n", error);
Do_log_error(error_msg);
exit(SOCKET_CREATE_ERROR);
}
/* set up the bind address */
bind_address.sin_family = AF_INET;
bind_address.sin_addr.s_addr = INADDR_ANY;
bind_address.sin_port = PHANTASIA_PORT;
/* bind to that socket */
error = bind(the_socket, (struct sockaddr *) &bind_address,
sizeof(bind_address));
if (error != 0) {
sprintf(error_msg, "[0.0.0.0:?] bind to socket failed with error code of %d in Do_init_server_socket.\n", error);
Do_log_error(error_msg);
exit(SOCKET_BIND_ERROR);
}
/* start listening on the socket */
error = listen(the_socket, SOMAXCONN);
if (error != 0) {
sprintf(error_msg, "[0.0.0.0:?] listen command failed with error code of %d in Do_init_server_socket\n", error);
Do_log_error(error_msg);
exit(SOCKET_LISTEN_ERROR);
}
if (error = fcntl(the_socket, F_SETOWN, getpid()) < 0) {
sprintf(error_msg, "[0.0.0.0:?] fcntl F_SETOWN failed with error code of %d in Do_init_server_socket.\n", error);
Do_log_error(error_msg);
exit(SOCKET_BIND_ERROR);
}
if (error = fcntl(the_socket, F_SETFL, O_ASYNC) < 0) {
sprintf(error_msg, "[0.0.0.0:?] fcntl F_SETFL failed with error code of %d in Do_init_server_socket.\n", error);
Do_log_error(error_msg);
exit(SOCKET_BIND_ERROR);
}
return the_socket; /* no problems */
}
/************************************************************************
/
/ FUNCTION NAME: Do_accept_connections(struct server_t *s)
/
/ FUNCTION: Create new games for new connections on the socket
/
/ AUTHOR: Brian Kelly, 4/12/99
/
/ ARGUMENTS:
/ struct server_t *s - address of the server's main data strcture
/
/ RETURN VALUE: int error
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/ This routine is specially designed to:
/
/ - strip non-printing characters (unless Wizard)
/ - echo, if desired
/ - redraw the screen if CH_REDRAW is entered
/ - read in only 'mx - 1' characters or less characters
/ - nul-terminate string, and throw away newline
/
/ 'mx' is assumed to be at least 2.
/
*************************************************************************/
int Do_accept_connections(struct server_t *s)
{
struct game_t *game_ptr;
struct client_t *client_ptr;
pthread_attr_t thread_attr;
size_t addrlen;
char error_msg[SZ_ERROR_MESSAGE];
int theError, on=1, terms, itemp;
char gethost_buffer[16384], *string_ptr, *string_ptr_two;
struct hostent *host_info, host_buffer;
struct in_addr theNetwork;
while (Do_check_socket(s->the_socket)) {
/* on a new connection, seed the random number generator */
srandom_r (time(NULL), (struct random_data *)&randData);
/* create a structure for the thread information */
client_ptr = (struct client_t *) Do_malloc(SZ_CLIENT);
/* accept the new connection */
addrlen = sizeof(client_ptr->address);
errno = 0;
client_ptr->socket = accept(s->the_socket,
(struct sockaddr *)&client_ptr->address, &addrlen);
if (client_ptr->socket == -1) {
sprintf(error_msg,
"[0.0.0.0:%d] accept socket failed in Do_accept_connections: %s.\n",
s->realm.serverPid, strerror(errno));
Do_log_error(error_msg);
free((void *)client_ptr);
return SOCKET_ACCEPT_ERROR;
}
/* log the connection */
sprintf(error_msg, "New connection on socket %d.\n",
client_ptr->socket);
Do_log(SERVER_LOG, error_msg);
/* set the socket variables */
client_ptr->socket_up = TRUE;
client_ptr->out_buffer_size = 0;
client_ptr->in_buffer_size = 0;
client_ptr->date_connected = time(NULL);
client_ptr->run_level = SIGNING_IN;
client_ptr->machineID = 0;
client_ptr->events = NULL;
client_ptr->channel = 1;
client_ptr->timeout = 120;
client_ptr->timeoutFlag = 0;
client_ptr->broadcast = FALSE;
client_ptr->stuck = FALSE;
client_ptr->knightEnergy = 0;
client_ptr->knightQuickness = 0;
client_ptr->ageCount = 0;
client_ptr->morgothCount = 0;
client_ptr->suspended = FALSE;
client_ptr->accountLoaded = FALSE;
client_ptr->characterLoaded = FALSE;
client_ptr->characterAnnounced = FALSE;
client_ptr->muteUntil = 0;
client_ptr->tagUntil = 0;
client_ptr->hearBroadcasts = TRUE;
client_ptr->swearCount = 0;
client_ptr->battle.rounds = 0;
client_ptr->battle.timeouts = 0;
client_ptr->previousName[0] = '\0';
client_ptr->wizaccount[0] = '\0';
client_ptr->wizIP[0] = '\0';
for (terms = 0; terms < 10; terms++) {
client_ptr->chatTimes[terms] = 0;
client_ptr->chatLength[terms] = 0;
}
/* set the from and name fields */
/* determine the dns entry of this connection */
/* I've had major problems getting the reentrant fuction
working with linux as it is not standard. I hope the normal
function run in main process is okay */
host_info = NULL;
theError = 0;
/*
gethostbyaddr_r((char *)&client_ptr->address.sin_addr,
sizeof(client_ptr->address.sin_addr), AF_INET, &host_buffer,
gethost_buffer, 16384, &host_info, &theError);
*/
/*
errno = 0;
host_info = gethostbyaddr((char *)&client_ptr->address.sin_addr,
sizeof(client_ptr->address.sin_addr), AF_INET);
theError = errno;
*/
/* if we received host information */
if (host_info != NULL) {
/* copy over the hostname */
strncpy(&client_ptr->IP, host_info->h_name, SZ_FROM - 1);
client_ptr->IP[SZ_FROM - 1] = '\0';
/* determine the network address of this connection */
string_ptr = client_ptr->IP;
/* skip the first term (assume host name) */
while (*string_ptr != '\0' && *string_ptr++ != '.') {}
/* if we found a null, there is no network (local machine) */
if (*string_ptr == '\0') {
strncpy(client_ptr->network, client_ptr->IP, SZ_FROM - 1);
client_ptr->network[SZ_FROM - 1] = '\0';
client_ptr->addressResolved = FALSE;
}
else {
/* count the number or remaining terms */
terms = 1;
string_ptr_two = string_ptr;
while (*string_ptr_two != '\0') {
if (*string_ptr_two++ == '.')
++terms;
}
/* remove terms until we find one without numbers or hex or
we have only two terms left */
string_ptr_two = string_ptr;
while (*string_ptr != '\0' || terms > 2) {
if (isxdigit(*string_ptr)) {
++string_ptr;
}
else if (*string_ptr == '.') {
string_ptr_two = ++string_ptr;
}
else {
break;
}
}
/* put this shortened hostname into place */
strncpy(client_ptr->network, string_ptr_two, SZ_FROM - 1);
client_ptr->network[SZ_FROM - 1];
client_ptr->addressResolved = TRUE;
}
}
else {
/* use the IP address */
string_ptr = (char *) inet_ntoa(client_ptr->address.sin_addr);
strncpy(client_ptr->IP, string_ptr, SZ_FROM - 1);
client_ptr->IP[SZ_FROM - 1] = '\0';
/* get the class C network address */
theNetwork.s_addr = client_ptr->address.sin_addr.s_addr &
0x00FFFFFF;
client_ptr->addressResolved = FALSE;
string_ptr = (char *) inet_ntoa(theNetwork);
strncpy(client_ptr->network, string_ptr, SZ_FROM - 1);
client_ptr->network[SZ_FROM - 1] = '\0';
/* stop logging this an an error - too common */
/*
sprintf(error_msg,
"[%s:?] gethostbyaddress returned error %d in Do_accept_connections.\n",
client_ptr->IP, theError);
Do_log_error(error_msg);
*/
}
sprintf(error_msg, "Connection, IP=%s, Network=%s.\n", client_ptr->IP, client_ptr->network);
Do_log(DEBUG_LOG, error_msg);
/* create a new game object */
game_ptr = (struct game_t *) Do_malloc(SZ_GAME);
/* set up the game variables */
game_ptr->cleanup_thread = FALSE;
game_ptr->virtual = FALSE;
game_ptr->hearAllChannels = HEAR_SELF;
game_ptr->chatFilter = TRUE;
game_ptr->sendEvents = FALSE;
game_ptr->the_socket = client_ptr->socket;
game_ptr->description = NULL;
game_ptr->it_combat = NULL;
game_ptr->events_in = NULL;
game_ptr->account[0] = '\0';
strcpy(game_ptr->IP, client_ptr->IP);
strcpy(game_ptr->network, client_ptr->network);
game_ptr->machineID = 0;
/* initialize the event queue locks */
Do_init_mutex(&game_ptr->events_in_lock);
/* lock the game list */
Do_lock_mutex(&s->realm.realm_lock);
/* put the temp game into the list of games */
game_ptr->next_game = s->realm.games;
s->realm.games = game_ptr;
/* unlock the game list */
Do_unlock_mutex(&s->realm.realm_lock);
/* init the pthread_att strcture */
theError = pthread_attr_init(&thread_attr);
if (theError) {
sprintf(error_msg, "[0.0.0.0:%d] init of pthread_attr_t failed with error code of %d in Do_accept_connections.\n", s->realm.serverPid, theError);
Do_log_error(error_msg);
free((void *)client_ptr);
return PTHREAD_ATTR_ERROR;
}
/*
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&thread_attr, 0xfffffff);
*/
/* set up all information to be passed to the thread */
client_ptr->realm = &s->realm;
client_ptr->game = game_ptr;
/* create the new thread */
theError = pthread_create(&game_ptr->the_thread, NULL,
Do_start_thread, (void *)client_ptr);
if (theError) {
sprintf(error_msg, "[0.0.0.0:%d] thread creation failed with an error code of %d in Do_accept_connections.\n", s->realm.serverPid, theError);
Do_log_error(error_msg);
free((void *)client_ptr);
return PTHREAD_CREATE_ERROR;
}
++s->num_games;
}
return 0;
}
/************************************************************************
/
/ FUNCTION NAME: Do_check_socket(int the_socket)
/
/ FUNCTION: Checks for data waiting on the socket
/
/ AUTHOR: Brian Kelly, 4/23/99
/
/ ARGUMENTS:
/ int the_socket - the socket to check for data
/
/ RETURN VALUE:
/ bool - true if there is data waiting on the socket
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/ This routine is specially designed to:
/
*************************************************************************/
int Do_check_socket(int the_socket)
{
fd_set rmask;
static struct timeval timeout = { 0, 0 }; /* no timeout */
char error_msg[SZ_ERROR_MESSAGE];
int error;
/* set rmask to check our socket */
FD_ZERO(&rmask);
FD_SET(the_socket, &rmask);
/* check for connections to be accepted */
error = select(the_socket + 1, &rmask, 0, 0, &timeout);
if (error < 0) {
sprintf(error_msg, "[0.0.0.0:?] select on socket failed with error code of %d in Do_check_socket\n", error);
Do_log_error(error_msg);
exit(SOCKET_SELECT_ERROR);
}
/* if select found no matches, return */
if (error == 0) {
return FALSE;
}
/* if our socket flag is not set, something is wrong */
if (!FD_ISSET(the_socket, &rmask)) {
sprintf(error_msg, "[0.0.0.0:?] select returned %d, but socket flag is off in Do_check_socket.\n", error);
Do_log_error(error_msg);
exit (SOCKET_SELECT_ERROR);
}
return TRUE;
}
/************************************************************************
/
/ FUNCTION NAME: Do_send_buffer(int the_socket)
/
/ FUNCTION: Send data over the socket to the player
/
/ AUTHOR: Brian Kelly, 4/23/99
/
/ ARGUMENTS:
/ int the_socket - the socket to send the information on
/ size_t the_size - the number of byest to send
/ void *the_data - a pointer to the data to be sent
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/ This routine is specially designed to:
/
*************************************************************************/
Do_send_buffer(struct client_t *c)
{
/*
char error_msg[SZ_ERROR_MESSAGE];
*/
char error_msg[2048];
int bytes_sent;
if (c->socket_up && c->out_buffer_size > 0) {
/* send off the data */
errno = 0;
c->out_buffer[c->out_buffer_size] = '\0';
#ifdef SEND_DEBUG
sprintf(error_msg, "[%s] sending %d bytes\n", c->connection_id,
c->out_buffer_size);
Do_log(DEBUG_LOG, error_msg);
#endif
#ifdef SEND_PACKET_DEBUG
sprintf(error_msg, "[%s] (%s)\n", c->connection_id, c->out_buffer);
Do_log(DEBUG_LOG, error_msg);
#endif
bytes_sent = send(c->socket, c->out_buffer, c->out_buffer_size, 0);
if (bytes_sent != c->out_buffer_size) {
sprintf(error_msg,
"[%s] send on socket sent %d out of %d bytes in Do_send_buffer: %s.\n",
c->connection_id, bytes_sent, c->out_buffer_size, strerror(errno));
Do_log_error(error_msg);
c->socket_up = FALSE;
sprintf(error_msg, "[%s] Error on socket while sending.\n",
c->connection_id);
Do_log(CONNECTION_LOG, error_msg);
}
c->out_buffer_size = 0;
}
return;
}
/************************************************************************
/
/ FUNCTION NAME: Do_send_out(struct client_t *c, void *the_data, size_t the_size)
/
/ FUNCTION: Send data over the socket to the player
/
/ AUTHOR: Brian Kelly, 5/6/99
/
/ ARGUMENTS:
/ int the_socket - the socket to send the information on
/ size_t the_size - the number of byest to send
/ void *the_data - a pointer to the data to be sent
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/ This routine is specially designed to:
/
*************************************************************************/
Do_send_out(struct client_t *c, void *the_data, size_t the_size)
{
char error_msg[SZ_ERROR_MESSAGE];
char string_buffer[SZ_LINE], string_buffer2[SZ_LINE];
if (c->socket_up) {
if (the_size > SZ_OUT_BUFFER) {
sprintf(error_msg,
"[%s] buffer_out overflow with %d bytes in Do_send_out.\n",
c->connection_id, the_size);
Do_log_error(error_msg);
Do_send_error(c, error_msg);
c->socket_up = FALSE;
return;
}
if (the_size + c->out_buffer_size > SZ_OUT_BUFFER) {
Do_send_buffer(c);
if (the_size + c->out_buffer_size > SZ_OUT_BUFFER) {
return;
}
}
#ifdef SEND_QUEUE_DEBUG
memcpy(string_buffer, the_data, the_size);
/* remove the "\n" */
string_buffer[the_size - 1] = '\0';
sprintf(string_buffer2, "[%s] Queued (%s)\n", c->connection_id,
string_buffer);
Do_log(DEBUG_LOG, string_buffer2);
#endif
memcpy(&c->out_buffer[c->out_buffer_size], the_data, the_size);
c->out_buffer_size += the_size;
}
return;
}
/************************************************************************
/
/ FUNCTION NAME: Do_send_string(struct client_t *c, char *theMessage)
/
/ FUNCTION: Send data over the socket to the player
/
/ AUTHOR: Brian Kelly, 8/11/99
/
/ ARGUMENTS:
/ int the_socket - the socket to send the information on
/ size_t the_size - the number of byest to send
/ void *the_data - a pointer to the data to be sent
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/ This routine is specially designed to:
/
*************************************************************************/
Do_send_string(struct client_t *c, char *theMessage)
{
int theSize;
/* determine the string size */
theSize = strlen(theMessage);
/* send the data */
Do_send_out(c, theMessage, theSize);
return;
}
/************************************************************************
/
/ FUNCTION NAME: Do_send_double(struct client_t *c, double theDouble)
/
/ FUNCTION: Send data over the socket to the player
/
/ AUTHOR: Brian Kelly, 8/13/99
/
/ ARGUMENTS:
/ int the_socket - the socket to send the information on
/ size_t the_size - the number of byest to send
/ void *the_data - a pointer to the data to be sent
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/ This routine is specially designed to:
/
*************************************************************************/
Do_send_double(struct client_t *c, double theDouble)
{
char tmpDouble[SZ_NUMBER];
/* determine the string size */
sprintf(tmpDouble, "%0.lf\n", theDouble);
/* send the data */
Do_send_string(c, tmpDouble);
return;
}
/************************************************************************
/
/ FUNCTION NAME: Do_send_float(struct client_t *c, float theFloat)
/
/ FUNCTION: Send data over the socket to the player
/
/ AUTHOR: Brian Kelly, 8/13/99
/
/ ARGUMENTS:
/ int the_socket - the socket to send the information on
/ size_t the_size - the number of byest to send
/ void *the_data - a pointer to the data to be sent
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/ This routine is specially designed to:
/
*************************************************************************/
Do_send_float(struct client_t *c, double theFloat)
{
char tmpFloat[SZ_NUMBER];
/* determine the string size */
sprintf(tmpFloat, "%0.lf\n", theFloat);
/* send the data */
Do_send_string(c, tmpFloat);
return;
}
/************************************************************************
/
/ FUNCTION NAME: Do_send_fpfloat(struct client_t *c, float theFloat)
/
/ FUNCTION: Send a full-precision float to the client
/
/ AUTHOR: Brian Kelly, 8/25/99
/
/ ARGUMENTS:
/ int the_socket - the socket to send the information on
/ size_t the_size - the number of byest to send
/ void *the_data - a pointer to the data to be sent
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/ This routine is specially designed to:
/
*************************************************************************/
Do_send_fpfloat(struct client_t *c, double theFloat)
{
char tmpFloat[SZ_NUMBER];
/* determine the string size */
sprintf(tmpFloat, "%.4lf\n", theFloat);
/* send the data */
Do_send_string(c, tmpFloat);
return;
}
/************************************************************************
/
/ FUNCTION NAME: Do_send_int(struct client_t *c, int theInt)
/
/ FUNCTION: Send data over the socket to the player
/
/ AUTHOR: Brian Kelly, 8/13/99
/
/ ARGUMENTS:
/ int the_socket - the socket to send the information on
/ size_t the_size - the number of byest to send
/ void *the_data - a pointer to the data to be sent
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/ This routine is specially designed to:
/
*************************************************************************/
Do_send_int(struct client_t *c, int theInt)
{
char tmpInt[SZ_NUMBER];
/* determine the string size */
sprintf(tmpInt, "%d\n", theInt);
/* send the data */
Do_send_string(c, tmpInt);
return;
}
/************************************************************************
/
/ FUNCTION NAME: Do_send_short(struct client_t *c, short theShort)
/
/ FUNCTION: Send data over the socket to the player
/
/ AUTHOR: Brian Kelly, 8/13/99
/
/ ARGUMENTS:
/ int the_socket - the socket to send the information on
/ size_t the_size - the number of byest to send
/ void *the_data - a pointer to the data to be sent
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/ This routine is specially designed to:
/
*************************************************************************/
Do_send_short(struct client_t *c, short theShort)
{
char tmpShort[SZ_NUMBER];
/* determine the string size */
sprintf(tmpShort, "%hd\n", theShort);
/* send the data */
Do_send_string(c, tmpShort);
return;
}
/************************************************************************
/
/ FUNCTION NAME: Do_send_bool(struct client_t *c, bool theBool)
/
/ FUNCTION: Send data over the socket to the player
/
/ AUTHOR: Brian Kelly, 8/13/99
/
/ ARGUMENTS:
/ int the_socket - the socket to send the information on
/ size_t the_size - the number of byest to send
/ void *the_data - a pointer to the data to be sent
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/ This routine is specially designed to:
/
*************************************************************************/
Do_send_bool(struct client_t *c, short theBool)
{
if (theBool == FALSE)
/* send the data */
Do_send_string(c, "No\n");
else
/* send the data */
Do_send_string(c, "Yes\n");
return;
}
/************************************************************************
/
/ FUNCTION NAME: Do_send_error(struct client_t *c, char *theError)
/
/ FUNCTION: Send data over the socket to the player
/
/ AUTHOR: Brian Kelly, 10/2/99
/
/ ARGUMENTS:
/ int the_socket - the socket to send the information on
/ size_t the_size - the number of byest to send
/ void *the_data - a pointer to the data to be sent
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/ This routine is specially designed to:
/
*************************************************************************/
Do_send_error(struct client_t *c, char *theError)
{
Do_send_int(c, ERROR_PACKET);
Do_send_string(c, theError);
Do_send_buffer(c);
return;
}
/************************************************************************
/
/ FUNCTION NAME: Do_read_socket(struct client_t *c)
/
/ FUNCTION: Send data over the socket to the player
/
/ AUTHOR: Brian Kelly, 4/24/99
/
/ ARGUMENTS:
/ int the_socket - the socket to read data from
/ size_t the_size - the number of bytes to read from the socket
/ void *the_data - a pointer to the data to be read
/
/ RETURN VALUE: none
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/ This routine is specially designed to:
/
*************************************************************************/
Do_read_socket(struct client_t *c)
{
char error_msg[SZ_ERROR_MESSAGE];
int bytes_read;
struct event_t *event_ptr;
errno = 0;
/* read the data from the socket */
bytes_read = recv(c->socket, &c->in_buffer[c->in_buffer_size],
(SZ_IN_BUFFER - c->in_buffer_size), 0);
if (bytes_read <= 0) {
/* the socket is no longer any good */
c->socket_up = FALSE;
/* if client closed abruptly, the connection will be reset */
if (errno = ECONNRESET) {
/* Error too common for the error log */
/*
sprintf(error_msg,
"[%s] Received a ECONNRESET on socket in Do_read_socket.\n",
c->connection_id);
Do_log_error(error_msg);
*/
}
else {
sprintf(error_msg,
"[%s] read on socket returned %d bytes in Do_read_socket: %s\n",
c->connection_id, bytes_read, strerror(errno));
Do_log_error(error_msg);
}
sprintf(error_msg, "[%s] Received an error on the socket.\n",
c->connection_id);
Do_log(CONNECTION_LOG, error_msg);
}
else if (bytes_read + c->in_buffer_size > SZ_IN_BUFFER) {
/* the socket is no longer any good */
c->socket_up = FALSE;
/* log an error */
sprintf(error_msg, "[%s] added %d to %d bytes for in_buffer overvlow in Do_read_socket.\n", c->connection_id, bytes_read, c->in_buffer_size);
Do_log_error(error_msg);
}
else {
c->in_buffer_size += bytes_read;
}
return;
}
/************************************************************************
/
/ FUNCTION NAME: Do_get_socket_string(struct client_t *c, void *the_data, size_t the_size)
/
/ FUNCTION: reads the next packet type off the socket
/
/ AUTHOR: Brian Kelly, 4/23/99
/
/ ARGUMENTS:
/ int the_socket - the socket to read the packet type
/
/ RETURN VALUE:
/ int - the type of packet next on the socket
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/
/************************************************************************/
int Do_get_socket_string(struct client_t *c, char *theString, size_t theSize)
{
size_t theLength;
char string_buffer[SZ_LINE], error_msg[SZ_ERROR_MESSAGE + SZ_OUT_BUFFER];
sigset_t sigMask;
int theSignal;
/* prepare to unblock SIGIO */
sigemptyset(&sigMask);
sigaddset(&sigMask, SIGIO);
sigaddset(&sigMask, SIGALRM);
for (;;) {
/* if the socket is down, return an error */
if (!c->socket_up) {
return S_ERROR;
}
/* if we have information in the buffer */
if (c->in_buffer_size) {
/* see if the entire string has been downloaded */
theLength = strlen(c->in_buffer);
if (theLength < c->in_buffer_size) {
/* check that the passed pointer can handle the size */
if (theSize - 1 < theLength) {
/* log the error */
sprintf(error_msg, "[%s] Client returned a string of %d bytes, %d max in Do_get_socket_string.\n", c->connection_id, theLength, theSize);
Do_log_error(error_msg);
/* get as much of the string as we can */
strncpy(theString, c->in_buffer, theSize - 1);
theString[theSize - 1] = '\0';
}
else {
strcpy(theString, c->in_buffer);
}
/* add the terminating null to the string */
++theLength;
/* move up information in the buffer */
if (theLength < c->in_buffer_size) {
c->in_buffer_size -= theLength;
memmove(c->in_buffer, &c->in_buffer[theLength],
c->in_buffer_size);
}
else {
c->in_buffer_size = 0;
}
#ifdef RECEIVE_DEBUG
sprintf(error_msg, "[%s] received %d bytes\n",
c->connection_id, theLength);
Do_log(DEBUG_LOG, error_msg);
#endif
#ifdef RECEIVE_PACKET_DEBUG
sprintf(error_msg, "[%s] (%s)\n", c->connection_id, theString);
Do_log(DEBUG_LOG, error_msg);
#endif
return S_NORM;
}
/* the the buffer is maxed and we're here,
the string is too large for the buffer */
if (c->in_buffer_size == SZ_IN_BUFFER) {
sprintf(error_msg, "[%s] Request for a string, %d bytes, larger than buffer in Do_get_socket_string.\n", c->connection_id, theLength);
Do_log_error(error_msg);
c->socket_up = FALSE;
return S_ERROR;
}
}
/* We need to wait for information, so pause */
if (c->socket_up) {
#ifdef SUSPEND_DEBUG
sprintf(error_msg,
"[%s] now sleeping with alarm set for %d seconds.\n",
c->connection_id, c->timeout);
Do_log(DEBUG_LOG, error_msg);
#endif
sigwait(&sigMask, &theSignal);
#ifdef SUSPEND_DEBUG
sprintf(error_msg, "[%s] awoken on signal %d.\n",
c->connection_id, theSignal);
Do_log(DEBUG_LOG, error_msg);
#endif
/*
sleep(.1);
*/
}
else {
theSignal = SIGIO;
}
/* check events and the socket on a SIGIO */
if (theSignal == SIGIO) {
/* if the socket is up, we have room in the buffer and
there is info waiting */
if (c->socket_up && c->in_buffer_size < SZ_IN_BUFFER &&
Do_check_socket(c->socket)) {
Do_read_socket(c);
}
/* see if any other threads have sent us an event */
Do_check_events_in(c);
}
/* see if the tread alarm went off */
else if (theSignal == SIGALRM) {
/*
if (time(NULL) > c->timeoutAt) {
*/
switch(++c->timeoutFlag) {
/* alarm has gone off once */
case 1:
Do_send_int(c, PING_PACKET);
Do_send_buffer(c);
/* give the client 15 seconds to respond */
alarm(15);
c->timeoutAt = time(NULL) + 15;
break;
/* gone off twice */
case 2:
sprintf(error_msg, "[%s] Socket connection timed out.\n",
c->connection_id);
Do_log(CONNECTION_LOG, error_msg);
Do_send_error(c, "The socket connection timed out.\n");
Do_send_buffer(c);
/* assume the network connection is down */
sprintf(error_msg,
"[%s] Socket connection timed out in Do_get_socket_string.\n",
c->connection_id);
Do_log_error(error_msg);
c->socket_up = FALSE;
return S_ERROR;
}
}
/* unknown signal */
else {
sprintf(error_msg, "[%s] Received unknown signal %d.\n",
c->connection_id, theSignal);
Do_log_error(error_msg);
}
}
}
/************************************************************************
/
/ FUNCTION NAME: Do_get_string(struct client_t *c, char *theString,
/ int maxSize);
/
/ FUNCTION: Wait until char is returned from player
/
/ AUTHOR: Brian Kelly, 8/11/99
/
/ ARGUMENTS:
/ client_t c - the client data strcture
/ size_t the_size - the number of bytes fo data expected
/ void *the_data - a pointer to where the data should be written
/ bool exact - Does there need to be exactly the_size bytes?
/
/ RETURN VALUE:
/ bool - Was the data or a timeout registered
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/
/************************************************************************/
int Do_get_string(struct client_t *c, char *theString, int maxSize)
{
char packetTmp[SZ_PACKET_TYPE], error_msg[SZ_ERROR_MESSAGE];
int packetType;
int returnCode;
Do_send_buffer(c);
c->timeoutFlag = 0;
alarm(c->timeout);
c->timeoutAt = time(NULL) + c->timeout;
for(;;) {
/* get the header of the next packet */
errno = 0;
if (Do_get_socket_string(c, packetTmp, SZ_PACKET_TYPE) == S_ERROR) {
alarm(0);
return S_ERROR;
}
/* convert the string to an integer */
packetType = strtol(packetTmp, NULL, 10);
switch(packetType) {
/* if the packet type is returning an answer */
case C_RESPONSE_PACKET:
/* read the string */
returnCode = Do_get_socket_string(c, theString, maxSize);
alarm(0);
return returnCode;
case C_CANCEL_PACKET:
alarm(0);
return S_CANCEL;
case C_PING_PACKET:
if (c->timeoutFlag == 1) {
alarm(0);
return S_TIMEOUT;
}
else {
sprintf(error_msg, "[%s] Received unexpected ping packet.\n",
c->connection_id);
Do_log_error(error_msg);
}
break;
default:
if (Do_packet(c, packetType) == S_ERROR) {
alarm(0);
return S_ERROR;
}
}
}
}
/************************************************************************
/
/ FUNCTION NAME: Do_get_double(struct client_t *c, double *theDouble);
/
/ FUNCTION: Wait until char is returned from player
/
/ AUTHOR: Brian Kelly, 8/11/99
/
/ ARGUMENTS:
/ client_t c - the client data strcture
/ size_t the_size - the number of bytes fo data expected
/ void *the_data - a pointer to where the data should be written
/ bool exact - Does there need to be exactly the_size bytes?
/
/ RETURN VALUE:
/ bool - Was the data or a timeout registered
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/
/************************************************************************/
int Do_get_double(struct client_t *c, double *theDouble)
{
char tmpDouble[SZ_NUMBER];
int rc;
if (rc = Do_get_string(c, tmpDouble, SZ_NUMBER) != S_NORM) {
return rc;
}
*theDouble = floor(strtod(tmpDouble, NULL));
/* insure that the number is finite */
if (!finite(*theDouble)) {
/* fix the number */
*theDouble = 0;
}
return S_NORM;
}
/************************************************************************
/
/ FUNCTION NAME: Do_get_long(struct client_t *c, long *theLong);
/
/ FUNCTION: Wait until char is returned from player
/
/ AUTHOR: Brian Kelly, 10/2/99
/
/ ARGUMENTS:
/ client_t c - the client data strcture
/ size_t the_size - the number of bytes fo data expected
/ void *the_data - a pointer to where the data should be written
/ bool exact - Does there need to be exactly the_size bytes?
/
/ RETURN VALUE:
/ bool - Was the data or a timeout registered
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/
/************************************************************************/
int Do_get_long(struct client_t *c, long *theLong)
{
char tmpLong[SZ_NUMBER];
int returnCode;
returnCode = Do_get_string(c, tmpLong, SZ_NUMBER);
if (returnCode != S_NORM) {
return returnCode;
}
*theLong = strtol(tmpLong, NULL, 10);
return S_NORM;
}
/************************************************************************
/
/ FUNCTION NAME: Do_get_nothing(struct client_t *c);
/
/ FUNCTION: Wait until char is returned from player
/
/ AUTHOR: Brian Kelly, 11/3/99
/
/ ARGUMENTS:
/ client_t c - the client data strcture
/ size_t the_size - the number of bytes fo data expected
/ void *the_data - a pointer to where the data should be written
/ bool exact - Does there need to be exactly the_size bytes?
/
/ RETURN VALUE:
/ bool - Was the data or a timeout registered
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/
/************************************************************************/
int Do_get_nothing(struct client_t *c)
{
char packetTmp[SZ_PACKET_TYPE];
char error_msg[SZ_ERROR_MESSAGE];
int packetType;
for(;;) {
/* if the socket is up, we have room in the buffer and
there is info waiting */
if (c->socket_up && c->in_buffer_size < SZ_IN_BUFFER &&
Do_check_socket(c->socket)) {
Do_read_socket(c);
}
/* if the socket is up, and the buffer has data */
if (c->socket_up && c->in_buffer_size) {
c->timeoutAt = time(NULL) + c->timeout;
/* get the header of the next packet */
if (Do_get_socket_string(c, packetTmp, SZ_PACKET_TYPE) == S_ERROR)
return S_ERROR;
/* convert the string to an integer */
packetType = strtol(packetTmp, NULL, 10);
switch(packetType) {
/* we're not expecting an answer */
case C_RESPONSE_PACKET:
case C_CANCEL_PACKET:
case C_PING_PACKET:
/* print an error message */
sprintf(error_msg,
"[%s] Unexpected packet type %d returned in Do_get_nothing.\n",
c->connection_id, packetType);
Do_log_error(error_msg);
Do_send_error(c, error_msg);
c->socket_up = FALSE;
return S_ERROR;
default:
if (Do_packet(c, packetType) == S_ERROR) {
return S_ERROR;
}
}
}
else {
return S_NORM;
}
}
}
/************************************************************************
/
/ FUNCTION NAME: int Do_packet(client_t *c, char packetType);
/
/ FUNCTION: Wait until char is returned from player
/
/ AUTHOR: Brian Kelly, 8/11/99
/
/ ARGUMENTS:
/ client_t c - the client data strcture
/ size_t the_size - the number of bytes fo data expected
/ void *the_data - a pointer to where the data should be written
/ bool exact - Does there need to be exactly the_size bytes?
/
/ RETURN VALUE:
/ bool - Was the data or a timeout registered
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/
/************************************************************************/
int Do_packet(struct client_t *c, int thePacket)
{
char numChars;
time_t timeNow;
struct event_t *event_ptr;
char error_msg[SZ_ERROR_MESSAGE];
char player_name[SZ_NAME];
char string_buffer[SZ_CHAT - 20];
long theLong;
/* switch on the type of event */
switch(thePacket) {
case C_CHAT_PACKET:
/* get the string to be sent and quit on error*/
if (Do_get_socket_string(c, string_buffer, SZ_CHAT - 20) == S_ERROR)
return S_ERROR;
/* mute null chat messages */
if (strlen(string_buffer) > 0) {
/* if the player is muted */
if (c->muteUntil < time(NULL)) {
/* send the chat message */
Do_chat(c, string_buffer);
}
}
/* get rid of old tags */
if(c->tagUntil < time(NULL))
{
Do_remove_prefix_suffix(c);
/* if(c->characterLoaded)
{
strcpy(string_buffer, c->player.name);
if(c->characterAnnounced)
{
Do_send_specification(c, REMOVE_PLAYER_EVENT);
}
strncpy(c->modifiedName, string_buffer, SZ_NAME - 1);
if(c->characterAnnounced)
{
Do_send_specification(c, ADD_PLAYER_EVENT);
Do_name(c);
}
} */
}
/* finished */
return S_NORM;
case C_EXAMINE_PACKET:
/* read player name and quit if there's an error */
if (Do_get_socket_string(c, player_name, SZ_NAME) == S_ERROR)
return S_ERROR;
/* request the info from the player */
event_ptr = (struct event_t *) Do_create_event();
event_ptr->type = REQUEST_RECORD_EVENT;
event_ptr->from = c->game;
if (!Do_send_character_event(c, event_ptr, player_name)) {
free((void *)event_ptr);
}
/* finished */
return S_NORM;
case C_SCOREBOARD_PACKET:
/* read starting record and quit if there's an error */
if (Do_get_socket_string(c, string_buffer, SZ_NAME) == S_ERROR)
return S_ERROR;
theLong = strtol(string_buffer, NULL, 10);
/* convert the string to an int */
Do_scoreboard(c, (int) theLong, TRUE);
/* finished */
return S_NORM;
case C_ERROR_PACKET:
/* see if the client included a message */
if (Do_get_socket_string(c, error_msg, SZ_ERROR_MESSAGE) !=
S_NORM) {
error_msg[0] = '\0';
}
/* log the error */
sprintf(string_buffer,
"[%s] Client returned an error packet in Do_packet: %s.\n",
c->connection_id, error_msg);
Do_log_error(string_buffer);
c->socket_up = FALSE;
return S_ERROR;
default:
/* print an error message */
sprintf(error_msg,
"[%s] Received unknown packet type %d in Do_packet.\n",
c->connection_id, thePacket);
Do_log_error(error_msg);
Do_send_error(c, error_msg);
c->socket_up = FALSE;
/* exit gracefully */
return S_ERROR;
}
}
/************************************************************************
/
/ FUNCTION NAME: int Do_get_network_address(client_t *c, int hostAddress, int subnetMask);
/
/ FUNCTION: Wait until char is returned from player
/
/ AUTHOR: Brian Kelly, 6/8/00
/
/ ARGUMENTS:
/ client_t c - the client data strcture
/ size_t the_size - the number of bytes fo data expected
/ void *the_data - a pointer to where the data should be written
/ bool exact - Does there need to be exactly the_size bytes?
/
/ RETURN VALUE:
/ bool - Was the data or a timeout registered
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/
/************************************************************************/
Do_get_network_address(struct in_addr *hostAddress, int subnetMask)
{
unsigned int bitMask;
/* create a bitmask. Ex: 8 mask = 0xffffff00 */
bitMask = pow(2, subnetMask) - 1;
bitMask = (unsigned int) 0xffffffff ^ bitMask;
/* return only the network portion of the hostAddress */
hostAddress->s_addr = bitMask & htonl(hostAddress->s_addr);
hostAddress->s_addr = ntohl(hostAddress->s_addr);
return;
}
/************************************************************************
/
/ FUNCTION NAME: int Do_check_host_address(int hostAddress, int networkAddress, int subnetMask);
/
/ FUNCTION: Wait until char is returned from player
/
/ AUTHOR: Brian Kelly, 6/8/00
/
/ ARGUMENTS:
/ client_t c - the client data strcture
/ size_t the_size - the number of bytes fo data expected
/ void *the_data - a pointer to where the data should be written
/ bool exact - Does there need to be exactly the_size bytes?
/
/ RETURN VALUE:
/ bool - Was the data or a timeout registered
/
/ MODULES CALLED: wmove(), _filbuf(), clearok(), waddstr(), wrefresh(),
/ wclrtoeol()
/
/ DESCRIPTION:
/ Read a string from the keyboard.
/
/************************************************************************/
int Do_check_host_address(struct in_addr *hostAddress, struct in_addr *networkAddress, int subnetMask)
{
struct in_addr checkAddress;
if (subnetMask < 0 || subnetMask > 24) {
return FALSE;
}
checkAddress.s_addr = hostAddress->s_addr;
Do_get_network_address(&checkAddress, subnetMask);
if (networkAddress->s_addr == checkAddress.s_addr) {
return TRUE;
}
return FALSE;
}