/*************************************************************************** * 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; }