/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* *
* Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Thanks to abaddon for proof-reading our comm.c and pointing out bugs. *
* Any remaining bugs are, of course, our work, not his. :) *
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************/
/*
* This file contains all of the OS-dependent stuff:
* startup, signals, BSD sockets for tcp/ip, i/o, timing.
*
* The data flow for input is:
* Game_loop ---> Read_from_descriptor ---> Read
* Game_loop ---> Read_from_buffer
*
* The data flow for output is:
* Game_loop ---> Process_Output ---> Write_to_descriptor -> Write
*
* The OS-dependent functions are Read_from_descriptor and Write_to_descriptor.
* -- Furey 26 Jan 1993
*/
#include <glib.h>
#include <sys/types.h>
#if defined(unix)
#include <sys/time.h>
#endif
#if defined(_WIN32)
#include <time.h>
#include <winsock2.h>
#endif
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdarg.h>
#include <merc.h>
#include <tables.h>
#include <interp.h>
#include <recycle.h>
#include <sys/stat.h>
#include <fcntl.h>
//#include <signal.h>
#if defined(MALLOC_DEBUG)
#include <malloc.h>
extern int malloc_debug args( ( int ) );
extern int malloc_verify args( ( void ) );
#endif
#if defined( WIN32 )
#include <sys/timeb.h> /*for _ftime(), uses _timeb struct*/
#endif
#if defined(unix)
#include <signal.h>
#include <unistd.h>
#include <sys/resource.h> /* for RLIMIT_NOFILE */
#endif
/*
* Socket and TCP/IP stuff.
*/
#if defined(macintosh) || defined(MSDOS) || defined(_WIN32)
const char echo_off_str [] = { '\0' };
const char echo_on_str [] = { '\0' };
const char go_ahead_str [] = { '\0' };
#endif
#if defined(interactive)
#include <net/errno.h>
#include <sys/fcntl.h>
#endif
#if defined(linux)
int close args( ( int fd ) );
int select args( ( int width, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout ) );
int socket args( ( int domain, int type, int protocol ) );
int gettimeofday args( ( struct timeval *tp, struct timezone *tzp ) );
#endif
#if defined(sequent)
int accept args( ( int s, struct sockaddr *addr, int *addrlen ) );
int bind args( ( int s, struct sockaddr *name, int namelen ) );
int close args( ( int fd ) );
int fcntl args( ( int fd, int cmd, int arg ) );
int getpeername args( ( int s, struct sockaddr *name, int *namelen ) );
int getsockname args( ( int s, struct sockaddr *name, int *namelen ) );
int gettimeofday args( ( struct timeval *tp, struct timezone *tzp ) );
#if !defined(htons)
u_short htons args( ( u_short hostshort ) );
#endif
int listen args( ( int s, int backlog ) );
#if !defined(ntohl)
u_long ntohl args( ( u_long hostlong ) );
#endif
int read args( ( int fd, char *buf, int nbyte ) );
int select args( ( int width, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout ) );
int setsockopt args( ( int s, int level, int optname, caddr_t optval,
int optlen ) );
int socket args( ( int domain, int type, int protocol ) );
int write args( ( int fd, char *buf, int nbyte ) );
#endif
extern void stop_idling args( ( CHAR_DATA *ch ) );
extern void init_descriptor args( ( int control ) );
extern bool read_from_descriptor args( ( DESCRIPTOR_DATA *d ) );
extern void nanny args( ( DESCRIPTOR_DATA *d, char *argument ) );
extern bool process_output args( ( DESCRIPTOR_DATA *d, bool fPrompt ) );
extern void read_from_buffer args( ( DESCRIPTOR_DATA *d ) );
/*
* Global variables.
DESCRIPTOR_DATA * descriptor_free;
DESCRIPTOR_DATA * descriptor_list;
*/
extern FILE * fpReserve; /* Reserved file handle */
extern bool god; /* All new chars are gods! */
extern bool merc_down; /* Shutdown */
extern bool wizlock; /* Game is wizlocked */
extern bool newlock; /* Game is newlocked */
extern char str_boot_time[MAX_INPUT_LENGTH];
extern char crypt_pwd[MAX_INPUT_LENGTH];
extern time_t current_time; /* Time of this pulse */
extern time_t boot_time;
extern int world_affects; /* World Affect bits */
extern bool MOBtrigger; /* act() switch */
extern int port,control;
extern void game_loop_unix args( ( int control ) );
extern int init_socket args( ( int port ) );
void init_memory_chunck args(());
/*
* OS-dependent local functions.
*/
#if defined(_WIN32)
void game_loop_unix args( ( int control ) );
bool read_from_descriptor args( ( DESCRIPTOR_DATA *d ) );
void init_descriptor args( ( int control ) );
bool write_to_descriptor args( ( int desc, char *txt, int length ) );
#endif
extern void my_log_handler args((const gchar *log_domain,GLogLevelFlags log_level, const gchar *message, gpointer user_data));
extern void glib_crit_handler args((const gchar *log_domain,GLogLevelFlags log_level, const gchar *message, gpointer user_data));
int main( int argc, char **argv )
{
struct timeval now_time;
/*
* Memory debugging if needed.
*/
#if defined(MALLOC_DEBUG)
malloc_debug( 2 );
#endif
#ifdef RLIMIT_NOFILE
#ifndef min
# define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
{
struct rlimit rlp;
(void)getrlimit(RLIMIT_NOFILE, &rlp);
rlp.rlim_cur=min(rlp.rlim_max,FD_SETSIZE);
(void)setrlimit(RLIMIT_NOFILE, &rlp);
}
#endif
/*
* Init time and encryption.
*/
init_memory_chunck();
g_log_set_handler (g_log_domain_glib, G_LOG_LEVEL_INFO, my_log_handler, NULL);
g_log_set_handler (g_log_domain_glib, G_LOG_LEVEL_CRITICAL, glib_crit_handler, NULL);
gettimeofday( &now_time, NULL );
current_time = (time_t) now_time.tv_sec;
boot_time = current_time;
str_cpy( str_boot_time, ctime( ¤t_time ) );
str_cpy( crypt_pwd, "Don't bother." );
/*
* Reserve one channel for our use.
*/
if ( ( fpReserve = fopen( NULL_FILE, "r" ) ) == NULL )
{
bug( "NULL_FILE",0 );
exit( 1 );
}
/*
* Get the port number.
*/
port = 4040; /* Lurking Fear II on port 4040 */
if ( argc > 1 )
{
if ( !is_number( argv[1] ) )
{
fprintf( stderr, "Usage: %s [port #]\n", argv[0] );
exit( 1 );
}
else if ( ( port = atoi( argv[1] ) ) <= 1024 )
{
fprintf( stderr, "Port number must be above 1024.\n" );
exit( 1 );
}
if (argv[2] && argv[2][0])
{
fCopyOver = TRUE;
control = atoi(argv[3]);
}
else
fCopyOver = FALSE;
}
/*
* Run the game.
*/
#if defined(_WIN32)
control = init_socket(port);
boot_db( );
log_string2( "Lurking Fear II is locked, cocked and ready to rock." );
game_loop_unix(control);
#endif
#if defined(unix)
if (!fCopyOver)
{
control = init_socket(port);
}
//init_signals(); /*For the use of the signal handler. -Ferric */
/*control = init_socket( port );*/
boot_db( );
sprintf( log_buf, "Lurking Fear II is rip, raring, and ready to go on port %d.", port );
log_string2( log_buf );
/* set the copyover varibles */
copyover_set = FALSE;
copyover_time = 0;
game_loop_unix( control );
close( control );
#endif
/*
* That's all, folks.
*/
log_string2( "Normal termination of game." );
exit( 0 );
return 0;
}
void game_loop_unix( int control )
{
static struct timeval null_time;
struct timeval last_time;
GSList *desc_list;
//15 seconds to wait on people
unsigned int seconds = 15;
#if defined(unix)
signal( SIGPIPE, SIG_IGN );
#endif
gettimeofday( &last_time, NULL );
current_time = (time_t) last_time.tv_sec;
/* Main loop */
while ( !merc_down )
{
fd_set in_set;
fd_set out_set;
fd_set exc_set;
DESCRIPTOR_DATA *d;
int maxdesc;
#if defined(MALLOC_DEBUG)
if ( malloc_verify( ) != 1 )
abort( );
#endif
/*
* Poll all active descriptors.
*/
FD_ZERO( &in_set );
FD_ZERO( &out_set );
FD_ZERO( &exc_set );
FD_SET( control, &in_set );
maxdesc = control;
/* kavirpoint
maxdesc = control * 2;
*/ desc_list = descriptor_list;
while ( desc_list != NULL )
{
d = (DESCRIPTOR_DATA*)desc_list->data;
maxdesc = UMAX( maxdesc, d->descriptor );
FD_SET( d->descriptor, &in_set );
FD_SET( d->descriptor, &out_set );
FD_SET( d->descriptor, &exc_set );
desc_list = g_slist_next(desc_list);
}
g_slist_free(desc_list);
//Timeout for blocking
null_time.tv_sec = seconds;
null_time.tv_usec = 0;
if ( select( FD_SETSIZE, &in_set, &out_set, &exc_set, &null_time ) < 0 )
{
bug( "Game_loop: select: poll",0 );
exit( 1 );
}
/*
* New connection?
*/
if ( FD_ISSET( control, &in_set ) )
init_descriptor( control );
/*
* Kick out the freaky folks. If thier socket has a exception.
*/
while ( desc_list != NULL )
{
d = (DESCRIPTOR_DATA*)desc_list->data;
if ( FD_ISSET( d->descriptor, &exc_set ) )
{
FD_CLR( d->descriptor, &in_set );
FD_CLR( d->descriptor, &out_set );
if ( d->character && d->connected == CON_PLAYING)
save_char_obj( d->character );
d->outbuf = g_string_assign(d->outbuf,"");;
close_socket( d );
log_string2("Socket Exception Caught");
}
desc_list = g_slist_next(desc_list);
}
g_slist_free(desc_list);
/*
* Process input.
*/
for ( desc_list = descriptor_list; desc_list != NULL; desc_list = g_slist_next(desc_list) )
{
d = (DESCRIPTOR_DATA*)desc_list->data;
d->fcommand = FALSE;
if ( FD_ISSET( d->descriptor, &in_set ) )
{
if ( d->character != NULL )
d->character->timer = 0;
/*
* Transfer all data incomming to d->incom
* if we had a issue with read_from_descriptor..
* close thier connection.
*/
if ( !read_from_descriptor( d ) )
{
FD_CLR( d->descriptor, &out_set );
if ( d->character != NULL && d->connected == CON_PLAYING )
save_char_obj( d->character );
d->outbuf = g_string_assign(d->outbuf,"");;
close_socket( d );
continue;
}
}
if ( d->character != NULL && d->character->wait > 0 )
{
--d->character->wait;
continue;
}
/*
* Transfer the data from d->incom to d->incomm
*/
read_from_buffer( d );
if ( d->incomm[0] != '\0' )
{
d->fcommand = TRUE;
stop_idling( d->character );
/* OLC */
if ( d->showstr_point )
show_string( d, d->incomm );
else
{
if ( d->pString )
string_add( d->character, d->incomm );
else
{
switch ( d->connected )
{
case CON_PLAYING:
if ( !run_olc_editor(d))
substitute_alias( d, d->incomm );
break;
default:
nanny( d, d->incomm );
break;
}
}
}
d->incomm[0] = '\0';
}
}
/*
* Autonomous game motion.
*/
update_handler( );
/*
* Output.
*/
for ( desc_list = descriptor_list; desc_list != NULL; desc_list = g_slist_next(desc_list) )
{
d = (DESCRIPTOR_DATA*)desc_list->data;
if ( ( d->fcommand || d->outbuf->len > 0 )
&& FD_ISSET(d->descriptor, &out_set) )
{
if ( !process_output( d, TRUE ) )
{
//Added d->connected = playing from Rom
if ( d->character != NULL && d->connected == CON_PLAYING )
save_char_obj( d->character );
d->outbuf = g_string_assign(d->outbuf,"");;
close_socket( d );
}
}
}
/*
* Synchronize to a clock.
* Sleep( last_time + 1/PULSE_PER_SECOND - now ).
* Careful here of signed versus unsigned arithmetic.
*/
#if defined(unix)
{
struct timeval now_time;
long secDelta;
long usecDelta;
gettimeofday( &now_time, NULL );
usecDelta = ((int) last_time.tv_usec) - ((int) now_time.tv_usec)
+ 1000000 / PULSE_PER_SECOND;
secDelta = ((int) last_time.tv_sec ) - ((int) now_time.tv_sec );
while ( usecDelta < 0 )
{
usecDelta += 1000000;
secDelta -= 1;
}
while ( usecDelta >= 1000000 )
{
usecDelta -= 1000000;
secDelta += 1;
}
if ( secDelta > 0 || ( secDelta == 0 && usecDelta > 0 ) )
{
struct timeval stall_time;
stall_time.tv_usec = usecDelta;
stall_time.tv_sec = secDelta;
if ( select( 0, NULL, NULL, NULL, &stall_time ) < 0 )
{
bug( "Game_loop: select: stall",0 );
exit( 1 );
}
}
}
#endif
#if defined(_WIN32)
{
int times_up;
int nappy_time;
struct timeb start_time;
struct timeb end_time;
ftime( &start_time );
times_up = 0;
while( times_up == 0 )
{
ftime( &end_time );
if ( ( nappy_time =
(int) ( 1000 *
(double) ( ( end_time.time - start_time.time ) +
( (double) ( end_time.millitm -
start_time.millitm ) /
1000.0 ) ) ) ) >=
(double)( 1000 / PULSE_PER_SECOND ) )
times_up = 1;
else
{
Sleep( (int) ( (double) ( 1000 / PULSE_PER_SECOND ) -
(double) nappy_time ) );
times_up = 1;
}
}
}
#endif
gettimeofday( &last_time, NULL );
current_time = (time_t) last_time.tv_sec;
}
return;
}