/*
* This file contains the socket code, used for accepting
* new connections as well as reading and writing to
* sockets, and closing down unused sockets.
*/
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>
#include <netdb.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
#include <sys/ioctl.h>
#include <errno.h>
/* including main header file */
#include "mud.h"
/* global variables */
fd_set fSet; /* the socket list for polling */
D_SOCKET * dsock_free = NULL; /* the socket free list */
D_SOCKET * dsock_list = NULL; /* the linked list of active sockets */
D_MOBILE * dmobile_free = NULL; /* the mobile free list */
D_MOBILE * dmobile_list = NULL; /* the mobile list of active mobiles */
/* mccp support */
const unsigned char compress_will [] = { IAC, WILL, TELOPT_COMPRESS, '\0' };
const unsigned char compress_will2 [] = { IAC, WILL, TELOPT_COMPRESS2, '\0' };
const unsigned char do_echo [] = { IAC, WONT, TELOPT_ECHO, '\0' };
const unsigned char dont_echo [] = { IAC, WILL, TELOPT_ECHO, '\0' };
/* local procedures */
void game_loop ( int control );
/* intialize shutdown state */
bool shut_down = FALSE;
int control;
/*
* This is where it all starts, nothing special.
*/
int main(int argc, char **argv)
{
bool fCopyOver;
/* get the current time */
current_time = time(NULL);
/* note that we are booting up */
log_string("Program starting.");
if (argc > 2 && atoi(argv[2]) > 0)
{
fCopyOver = TRUE;
control = atoi(argv[2]);
}
else fCopyOver = FALSE;
/* initialize the socket */
if (!fCopyOver)
control = init_socket();
/* load all external data */
load_muddata(fCopyOver);
/* main game loop */
game_loop(control);
/* close down the socket */
close(control);
/* terminated without errors */
log_string("Program terminated without errors.");
return 0;
}
void game_loop(int control)
{
D_SOCKET *dsock;
D_SOCKET *dsock_next;
static struct timeval tv;
struct timeval last_time, new_time;
extern fd_set fSet;
fd_set rFd;
long secs, usecs;
/* set this for the first loop */
gettimeofday(&last_time, NULL);
/* clear out the file socket set */
FD_ZERO(&fSet);
/* add control to the set */
FD_SET(control, &fSet);
/* copyover recovery */
for (dsock = dsock_list; dsock; dsock = dsock->next)
FD_SET(dsock->control, &fSet);
/* do this untill the program is shutdown */
while (!shut_down)
{
/* set current_time */
current_time = time(NULL);
/* copy the socket set */
memcpy(&rFd, &fSet, sizeof(fd_set));
/* wait for something to happen */
if (select(FD_SETSIZE, &rFd, NULL, NULL, &tv) < 0)
continue;
/* check for new connections */
if (FD_ISSET(control, &rFd))
{
struct sockaddr_in sock;
unsigned int socksize;
int newConnection;
socksize = sizeof(sock);
if ((newConnection = accept(control, (struct sockaddr*) &sock, &socksize)) >=0)
new_socket(newConnection);
}
/* poll sockets in the socket list */
for (dsock = dsock_list; dsock; dsock = dsock_next)
{
dsock_next = dsock->next;
/*
* Close sockects we are unable to read from.
*/
if (FD_ISSET(dsock->control, &rFd) && !read_from_socket(dsock))
{
close_socket(dsock, FALSE);
continue;
}
/* Ok, check for a new command */
next_cmd_from_buffer(dsock);
/* Is there a new command pending ? */
if (dsock->next_command[0] != '\0')
{
/* figure out how to deal with the incoming command */
switch(dsock->state)
{
default:
bug("Descriptor in bad state.");
break;
case STATE_NEW_NAME:
case STATE_NEW_PASSWORD:
case STATE_VERIFY_PASSWORD:
case STATE_ASK_PASSWORD:
handle_new_connections(dsock, dsock->next_command);
break;
case STATE_PLAYING:
handle_cmd_input(dsock, dsock->next_command);
break;
}
dsock->next_command[0] = '\0';
}
/* if the player quits or get's disconnected */
if (dsock->state == STATE_CLOSED) continue;
/* Send all new data to the socket and close it if any errors occour */
if (!flush_output(dsock))
close_socket(dsock, FALSE);
}
/* call the top-level update handler */
update_handler();
/*
* Here we sleep out the rest of the pulse, thus forcing
* SocketMud(tm) to run at PULSES_PER_SECOND pulses each second.
*/
gettimeofday(&new_time, NULL);
/* get the time right now, and calculate how long we should sleep */
usecs = (int) (last_time.tv_usec - new_time.tv_usec) + 1000000 / PULSES_PER_SECOND;
secs = (int) (last_time.tv_sec - new_time.tv_sec);
/*
* Now we make sure that 0 <= usecs < 1.000.000
*/
while (usecs < 0)
{
usecs += 1000000;
secs -= 1;
}
while (usecs >= 1000000)
{
usecs -= 1000000;
secs += 1;
}
/* if secs < 0 we don't sleep, since we have encountered a laghole */
if (secs > 0 || (secs == 0 && usecs > 0))
{
struct timeval sleep_time;
sleep_time.tv_usec = usecs;
sleep_time.tv_sec = secs;
if (select(0, NULL, NULL, NULL, &sleep_time) < 0)
continue;
}
/* reset the last time we where sleeping */
gettimeofday(&last_time, NULL);
update_handler ();
/* recycle sockets */
recycle_sockets();
}
}
/*
* Init_socket()
*
* Used at bootup to get a free
* socket to run the server from.
*/
int init_socket()
{
struct sockaddr_in my_addr;
int sockfd, reuse = 1;
/* let's grab a socket */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
/* setting the correct values */
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY;
my_addr.sin_port = htons(MUDPORT);
/* this actually fixes any problems with threads */
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) == -1)
{
perror("Error in setsockopt()");
exit(1);
}
/* bind the port */
bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr));
/* start listening already :) */
listen(sockfd, 3);
/* return the socket */
return sockfd;
}
/*
* New_socket()
*
* Initializes a new socket, get's the hostname
* and puts it in the active socket_list.
*/
bool new_socket(int sock)
{
struct sockaddr_in sock_addr;
pthread_attr_t attr;
/*pthread_t thread_lookup;
LOOKUP_DATA * lData; */
D_SOCKET * sock_new;
int argp = 1;
socklen_t size;
/* initialize threads */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
/*
* allocate some memory for a new socket if
* there is no free socket in the free_list
*/
if (dsock_free == NULL)
{
if ((sock_new = malloc(sizeof(*sock_new))) == NULL)
{
bug("New_socket: Cannot allocate memory for socket.");
abort();
}
}
else
{
sock_new = dsock_free;
dsock_free = dsock_free->next;
}
/* attach the new connection to the socket list */
FD_SET(sock, &fSet);
/* clear out the socket */
clear_socket(sock_new, sock);
/* set the socket as non-blocking */
ioctl(sock, FIONBIO, &argp);
/* update the linked list of sockets */
sock_new->next = dsock_list;
dsock_list = sock_new;
/* do a host lookup */
size = sizeof(sock_addr);
if (getpeername(sock, (struct sockaddr *) &sock_addr, &size) < 0)
{
perror("New_socket: getpeername");
sock_new->hostname = strdup("unknown");
}
else
{
/* set the IP number as the temporary hostname */
sock_new->hostname = strdup(inet_ntoa(sock_addr.sin_addr));
/*
if (!compares(sock_new->hostname, "127.0.0.1"))
{
allocate some memory for the lookup data
if ((lData = malloc(sizeof(*lData))) == NULL)
{
bug("New_socket: Cannot allocate memory for lookup data.");
abort();
}
Set the lookup_data for use in lookup_address()
lData->buf = strdup((char *) &sock_addr.sin_addr);
lData->dsock = sock_new;
dispatch the lookup thread
pthread_create(&thread_lookup, &attr, &lookup_address, (void*) lData);
}
else */
sock_new->lookup_status++;
}
/* negotiate compression */
text_to_buffer(sock_new, (char *) compress_will2);
text_to_buffer(sock_new, (char *) compress_will);
/* send the greeting */
text_to_buffer(sock_new, greeting);
text_to_buffer(sock_new, _TXT_GREETING);
/* everything went as it was supposed to */
return TRUE;
}
/*
* Close_socket()
*
* Will close one socket directly, freeing all
* resources and making the socket availably on
* the socket free_list.
*/
void close_socket(D_SOCKET *dsock, bool reconnect)
{
if (dsock->lookup_status > TSTATE_DONE) return;
dsock->lookup_status += 2;
/* remove the socket from the polling list */
FD_CLR(dsock->control, &fSet);
if (dsock->state == STATE_PLAYING)
{
if (reconnect)
text_to_socket(dsock, _TXT_SOCK_OVER);
else if (dsock->player)
{
dsock->player->socket = NULL;
log_string("Closing link to %s", dsock->player->name);
}
}
else if (dsock->player)
free_mobile(dsock->player);
/* set the closed state */
dsock->state = STATE_CLOSED;
}
/*
* Read_from_socket()
*
* Reads one line from the socket, storing it
* in a buffer for later use. Will also close
* the socket if it tries a buffer overflow.
*/
bool read_from_socket(D_SOCKET *dsock)
{
int size;
extern int errno;
/* check for buffer overflows, and drop connection in that case */
size = strlen(dsock->inbuf);
if (size >= sizeof(dsock->inbuf) - 2)
{
text_to_socket(dsock, _TXT_OVERFLOW);
return FALSE;
}
/* start reading from the socket */
for (;;)
{
int sInput;
int wanted = sizeof(dsock->inbuf) - 2 - size;
sInput = read(dsock->control, dsock->inbuf + size, wanted);
if (sInput > 0)
{
size += sInput;
if (dsock->inbuf[size-1] == '\n' || dsock->inbuf[size-1] == '\r')
break;
}
else if (sInput == 0)
{
log_string("Read_from_socket: EOF");
return FALSE;
}
else if (errno == EAGAIN || sInput == wanted)
break;
else
{
perror("Read_from_socket");
return FALSE;
}
}
dsock->inbuf[size] = '\0';
return TRUE;
}
/*
* Text_to_socket()
*
* Sends text directly to the socket,
* will compress the data if needed.
*/
bool text_to_socket(D_SOCKET *dsock, const char *txt)
{
int iBlck, iPtr, iWrt = 0, length, control = dsock->control;
length = strlen(txt);
/* write compressed */
if (dsock && dsock->out_compress)
{
dsock->out_compress->next_in = (unsigned char *) txt;
dsock->out_compress->avail_in = length;
while (dsock->out_compress->avail_in)
{
dsock->out_compress->avail_out = COMPRESS_BUF_SIZE - (dsock->out_compress->next_out - dsock->out_compress_buf);
if (dsock->out_compress->avail_out)
{
int status = deflate(dsock->out_compress, Z_SYNC_FLUSH);
if (status != Z_OK)
return FALSE;
}
length = dsock->out_compress->next_out - dsock->out_compress_buf;
if (length > 0)
{
for (iPtr = 0; iPtr < length; iPtr += iWrt)
{
iBlck = UMIN(length - iPtr, 4096);
if ((iWrt = write(control, dsock->out_compress_buf + iPtr, iBlck)) < 0)
{
perror("Text_to_socket (compressed):");
return FALSE;
}
}
if (iWrt <= 0) break;
if (iPtr > 0)
{
if (iPtr < length)
memmove(dsock->out_compress_buf, dsock->out_compress_buf + iPtr, length - iPtr);
dsock->out_compress->next_out = dsock->out_compress_buf + length - iPtr;
}
}
}
return TRUE;
}
/* write uncompressed */
for (iPtr = 0; iPtr < length; iPtr += iWrt)
{
iBlck = UMIN(length - iPtr, 4096);
if ((iWrt = write(control, txt + iPtr, iBlck)) < 0)
{
perror("Text_to_socket:");
return FALSE;
}
}
return TRUE;
}
/*
* Text_to_buffer()
*
* Stores outbound text in a buffer, where it will
* stay untill it is flushed in the gameloop.
*
* Will also parse ANSI colors and other tags.
*/
void text_to_buffer(D_SOCKET *dsock, const char *txt)
{
static char output[8 * MAX_BUFFER];
bool underline = FALSE, bold = FALSE;
int iPtr = 0, last = -1, j, k;
int length = strlen(txt);
/* the color struct */
struct sAnsiColor
{
const char cTag;
const char * cString;
int aFlag;
};
/* the color table... */
const struct sAnsiColor ansiTable[] =
{
{ 'd', "30", eTHIN },
{ 'D', "30", eBOLD },
{ 'r', "31", eTHIN },
{ 'R', "31", eBOLD },
{ 'g', "32", eTHIN },
{ 'G', "32", eBOLD },
{ 'y', "33", eTHIN },
{ 'Y', "33", eBOLD },
{ 'b', "34", eTHIN },
{ 'B', "34", eBOLD },
{ 'p', "35", eTHIN },
{ 'P', "35", eBOLD },
{ 'c', "36", eTHIN },
{ 'C', "36", eBOLD },
{ 'w', "37", eTHIN },
{ 'W', "37", eBOLD },
/* Background colors Used for Various stuff */
{ '1', "41", eTHIN}, /* Red */
{ '2', "42", eTHIN}, /* Green */
{ '3', "43", eTHIN}, /* Yellow */
{ '4', "44", eTHIN}, /* Blue */
{ '5', "45", eTHIN}, /* Magenta */
{ '6', "46", eTHIN}, /* Cyan */
{ '7', "47", eTHIN}, /* White */
/* Utility stuff */
{ 'x', "", eTHIN}, /* Clear */
/* the end tag */
{ '\0', "", eTHIN }
};
if (length >= MAX_BUFFER)
{
log_string("text_to_buffer: buffer overflow.");
return;
}
/* always start with a leading space */
if (dsock->top_output == 0)
{
dsock->outbuf[0] = '\n';
dsock->outbuf[1] = '\r';
dsock->top_output = 2;
}
while (*txt != '\0')
{
/* simple bound checking */
if (iPtr > (8 * MAX_BUFFER - 15))
break;
switch(*txt)
{
default:
output[iPtr++] = *txt++;
break;
case '#':
txt++;
/* toggle underline on/off with #u */
if (*txt == 'u')
{
txt++;
if (underline)
{
underline = FALSE;
output[iPtr++] = 27; output[iPtr++] = '['; output[iPtr++] = '0';
if (bold)
{
output[iPtr++] = ';'; output[iPtr++] = '1';
}
if (last != -1)
{
output[iPtr++] = ';';
for (j = 0; ansiTable[last].cString[j] != '\0'; j++)
{
output[iPtr++] = ansiTable[last].cString[j];
}
}
output[iPtr++] = 'm';
}
else
{
underline = TRUE;
output[iPtr++] = 27; output[iPtr++] = '[';
output[iPtr++] = '4'; output[iPtr++] = 'm';
}
}
/* parse ## to # */
else if (*txt == '#')
{
txt++;
output[iPtr++] = '#';
}
/* #n should clear all tags */
else if (*txt == 'n')
{
txt++;
if (last != -1 || underline || bold)
{
underline = FALSE;
bold = FALSE;
output[iPtr++] = 27; output[iPtr++] = '[';
output[iPtr++] = '0'; output[iPtr++] = 'm';
}
last = -1;
}
/* check for valid color tag and parse */
else
{
bool validTag = FALSE;
for (j = 0; ansiTable[j].cString[0] != '\0'; j++)
{
if (*txt == ansiTable[j].cTag)
{
validTag = TRUE;
/* we only add the color sequence if it's needed */
if (last != j)
{
bool cSequence = FALSE;
/* escape sequence */
output[iPtr++] = 27; output[iPtr++] = '[';
/* remember if a color change is needed */
if (last == -1 || last / 2 != j / 2)
cSequence = TRUE;
/* handle font boldness */
if (bold && ansiTable[j].aFlag == eTHIN)
{
output[iPtr++] = '0';
bold = FALSE;
if (underline)
{
output[iPtr++] = ';'; output[iPtr++] = '4';
}
/* changing to eTHIN wipes the old color */
output[iPtr++] = ';';
cSequence = TRUE;
}
else if (!bold && ansiTable[j].aFlag == eBOLD)
{
output[iPtr++] = '1';
bold = TRUE;
if (cSequence)
output[iPtr++] = ';';
}
/* add color sequence if needed */
if (cSequence)
{
for (k = 0; ansiTable[j].cString[k] != '\0'; k++)
{
output[iPtr++] = ansiTable[j].cString[k];
}
}
output[iPtr++] = 'm';
}
/* remember the last color */
last = j;
}
}
/* it wasn't a valid color tag */
if (!validTag)
output[iPtr++] = '#';
else
txt++;
}
break;
}
}
/* and terminate it with the standard color */
if (last != -1 || underline || bold)
{
output[iPtr++] = 27; output[iPtr++] = '[';
output[iPtr++] = '0'; output[iPtr++] = 'm';
}
output[iPtr] = '\0';
/* check to see if the socket can accept that much data */
if (dsock->top_output + iPtr >= MAX_OUTPUT)
{
bug("Text_to_buffer: ouput overflow on %s.", dsock->hostname);
close_socket(dsock, FALSE);
return;
}
/* add data to buffer */
strcpy(dsock->outbuf + dsock->top_output, output);
dsock->top_output += iPtr;
}
/*
* Text_to_mobile()
*
* If the mobile has a socket, then the data will
* be send to text_to_buffer().
*/
void text_to_mobile(D_MOBILE *dMob, const char *txt)
{
if (dMob->socket)
{
text_to_buffer(dMob->socket, txt);
dMob->socket->bust_prompt = TRUE;
}
}
void send_to_char(const char *txt, D_MOBILE *dMob)
{
if (dMob->socket)
{
text_to_buffer(dMob->socket, txt);
dMob->socket->bust_prompt = TRUE;
}
}
void next_cmd_from_buffer(D_SOCKET *dsock)
{
int size = 0, i = 0, j = 0, telopt = 0;
/* if theres already a command ready, we return */
if (dsock->next_command[0] != '\0')
return;
/* if there is nothing pending, then return */
if (dsock->inbuf[0] == '\0')
return;
/* check how long the next command is */
while (dsock->inbuf[size] != '\0' && dsock->inbuf[size] != '\n' && dsock->inbuf[size] != '\r')
size++;
/* we only deal with real commands */
if (dsock->inbuf[size] == '\0')
return;
/* copy the next command into next_command */
for ( ; i < size; i++)
{
if (dsock->inbuf[i] == (signed char) IAC)
{
telopt = 1;
}
else if (telopt == 1 && (dsock->inbuf[i] == (signed char) DO || dsock->inbuf[i] == (signed char) DONT))
{
telopt = 2;
}
else if (telopt == 2)
{
telopt = 0;
if (dsock->inbuf[i] == (signed char) TELOPT_COMPRESS) /* check for version 1 */
{
if (dsock->inbuf[i-1] == (signed char) DO) /* start compressing */
compressStart(dsock, TELOPT_COMPRESS);
else if (dsock->inbuf[i-1] == (signed char) DONT) /* stop compressing */
compressEnd(dsock, TELOPT_COMPRESS, FALSE);
}
else if (dsock->inbuf[i] == (signed char) TELOPT_COMPRESS2) /* check for version 2 */
{
if (dsock->inbuf[i-1] == (signed char) DO) /* start compressing */
compressStart(dsock, TELOPT_COMPRESS2);
else if (dsock->inbuf[i-1] == (signed char) DONT) /* stop compressing */
compressEnd(dsock, TELOPT_COMPRESS2, FALSE);
}
}
else if (isprint(dsock->inbuf[i]) && isascii(dsock->inbuf[i]))
{
dsock->next_command[j++] = dsock->inbuf[i];
}
}
dsock->next_command[j] = '\0';
/* skip forward to the next line */
while (dsock->inbuf[size] == '\n' || dsock->inbuf[size] == '\r')
{
dsock->bust_prompt = TRUE; /* seems like a good place to check */
size++;
}
/* use i as a static pointer */
i = size;
/* move the context of inbuf down */
while (dsock->inbuf[size] != '\0')
{
dsock->inbuf[size - i] = dsock->inbuf[size];
size++;
}
dsock->inbuf[size - i] = '\0';
}
bool flush_output(D_SOCKET *dsock)
{
/* nothing to send */
if (dsock->top_output <= 0 && !(dsock->bust_prompt && dsock->state == STATE_PLAYING))
return TRUE;
/* bust a prompt */
if (dsock->state == STATE_PLAYING && dsock->bust_prompt)
{
char buf[MAX_BUFFER];
sprintf(buf, "\n\r%dX @ %dY:> ", dsock->player->x, dsock->player->y);
text_to_buffer(dsock, buf);
dsock->bust_prompt = FALSE;
}
/* reset the top pointer */
dsock->top_output = 0;
/*
* Send the buffer, and return FALSE
* if the write fails.
*/
if (!text_to_socket(dsock, dsock->outbuf))
return FALSE;
/* Success */
return TRUE;
}
void handle_new_connections(D_SOCKET *dsock, char *arg)
{
D_MOBILE *p_new;
int i;
char bufxx[1024];
switch(dsock->state)
{
default:
bug("Handle_new_connections: Bad state.");
break;
case STATE_NEW_NAME:
if (dsock->lookup_status != TSTATE_DONE)
{
text_to_buffer(dsock, _TXT_LOGIN_DNS);
return;
}
if (!check_name(arg)) /* check for a legal name */
{
text_to_buffer(dsock, _TXT_ILLNAME);
break;
}
arg[0] = toupper(arg[0]);
log_string("%s is trying to connect.", arg);
/* Check for a new Player */
if ((p_new = load_profile(arg)) == NULL)
{
if (dmobile_free == NULL)
{
if ((p_new = malloc(sizeof(*p_new))) == NULL)
{
bug("Handle_new_connection: Cannot allocate memory.");
abort();
}
}
else
{
p_new = dmobile_free;
dmobile_free = dmobile_free->next;
}
clear_mobile(p_new);
/* give the player it's name */
p_new->name = strdup(arg);
/* prepare for next step */
text_to_buffer(dsock, _TXT_NEW_PASS);
dsock->state = STATE_NEW_PASSWORD;
}
else /* old player */
{
/* prepare for next step */
text_to_buffer(dsock, _TXT_OLD_PASS);
dsock->state = STATE_ASK_PASSWORD;
}
text_to_buffer(dsock, (char *) dont_echo);
/* socket <-> player */
p_new->socket = dsock;
dsock->player = p_new;
break;
case STATE_NEW_PASSWORD:
if (strlen(arg) < 5 || strlen(arg) > 12)
{
text_to_buffer(dsock, _TXT_PASS_LEN);
return;
}
dsock->player->password = strdup(crypt(arg, dsock->player->name));
for (i = 0; dsock->player->password[i] != '\0'; i++)
{
if (dsock->player->password[i] == '~')
{
text_to_buffer(dsock, _TXT_ILL_PASS);
return;
}
}
text_to_buffer(dsock, _TXT_PASS_VERI);
dsock->state = STATE_VERIFY_PASSWORD;
break;
case STATE_VERIFY_PASSWORD:
if (compares(crypt(arg, dsock->player->name), dsock->player->password))
{
text_to_buffer(dsock, (char *) do_echo);
/* put him in the list */
dsock->player->next = dmobile_list;
dmobile_list = dsock->player;
log_string("New player: %s has entered the game.", dsock->player->name);
/* and into the game */
dsock->state = STATE_PLAYING;
text_to_buffer(dsock, motd);
}
else
{
free(dsock->player->password);
text_to_buffer(dsock, _TXT_PASS_MISS);
dsock->state = STATE_NEW_PASSWORD;
}
break;
case STATE_ASK_PASSWORD:
text_to_buffer(dsock, (char *) do_echo);
if (compares(crypt(arg, dsock->player->name), dsock->player->password))
{
if ((p_new = check_reconnect(dsock->player->name)) != NULL)
{
/* attach the new player */
ex_free_mob(dsock->player);
dsock->player = p_new;
p_new->socket = dsock;
log_string("%s has reconnected.", dsock->player->name);
/* and let him enter the game */
dsock->state = STATE_PLAYING;
text_to_buffer(dsock, _TXT_BODY_USE);
}
else if ((p_new = load_player(dsock->player->name)) == NULL)
{
text_to_socket(dsock, _TXT_PFILE_BAD);
ex_free_mob(dsock->player);
dsock->player = NULL;
close_socket(dsock, FALSE);
return;
}
else
{
/* attach the new player */
ex_free_mob(dsock->player);
dsock->player = p_new;
p_new->socket = dsock;
/* put him in the active list */
p_new->next = dmobile_list;
dmobile_list = p_new;
log_string("%s has entered the game.", dsock->player->name);
/* and let him enter the game */
dsock->state = STATE_PLAYING;
text_to_buffer(dsock, motd);
cmd_look(dsock->player, "");
sprintf(bufxx, "%s has logged into %s", dsock->player->name, MUD_NAME);
mudwide_info(bufxx);
}
}
else
{
text_to_socket(dsock, _TXT_WRONG_PASS);
ex_free_mob(dsock->player);
dsock->player = NULL;
close_socket(dsock, FALSE);
}
break;
}
}
void clear_socket(D_SOCKET *sock_new, int sock)
{
bzero(sock_new, sizeof(*sock_new));
sock_new->control = sock;
sock_new->state = STATE_NEW_NAME;
sock_new->lookup_status = TSTATE_LOOKUP;
sock_new->player = NULL;
sock_new->top_output = 0;
}
/* does the lookup, changes the hostname, and dies */
void *lookup_address(void *arg)
{
LOOKUP_DATA *lData = (LOOKUP_DATA *) arg;
struct hostent *from = 0;
/*struct hostent ent;
char buf[16384];
int err;
*/
/* do the lookup and store the result at &from
gethostbyaddr(lData->buf, sizeof(lData->buf), AF_INET, &ent, buf, 16384, &from, &err);
*/
/* did we get anything ? */
if (from && from->h_name)
{
free(lData->dsock->hostname);
lData->dsock->hostname = strdup(from->h_name);
}
/* set it ready to be closed or used */
lData->dsock->lookup_status++;
/* free the lookup data */
free(lData->buf);
free(lData);
/* and kill the thread */
pthread_exit(0);
return 0;
}
void recycle_sockets()
{
D_SOCKET *dsock, *dsock_next;
for (dsock = dsock_list; dsock; dsock = dsock_next)
{
dsock_next = dsock->next;
if (dsock->lookup_status != TSTATE_CLOSED) continue;
/* remove the socket from the socket list */
if (dsock == dsock_list)
dsock_list = dsock->next;
else
{
D_SOCKET *prev;
for (prev = dsock_list; prev && prev->next != dsock; prev = prev->next)
;
if (prev)
prev->next = dsock->next;
else
bug("Recycle_sockets: Closed socket not in list");
}
/* close the socket */
close(dsock->control);
/* free the memory */
free(dsock->hostname);
/* stop compression */
compressEnd(dsock, dsock->compressing, TRUE);
/* put the socket in the free_list */
dsock->next = dsock_free;
dsock_free = dsock;
}
}