/************************************************************** * FFTacticsMUD : main.cpp * ************************************************************** * (c) 2002 Damien Dailidenas (Trenton). All rights reserved. * **************************************************************/ #include "main.h" #include <strstream> #include <cstdio> #include <sys/time.h> #include <csignal> #include <fcntl.h> #include <netdb.h> #include <sys/socket.h> #include <unistd.h> void init_signals args(()); void game_loop args((int control)); int init_socket args((int port)); void init_descriptor args((int control)); DESC *desc_list; CH *ch_list; AREA *area_list; BATTLE_AREA *battle_area_list; BATTLE *battle_list; bool game_down; string str_boot_time; time_t current_time; int port, control; extern string login_screen; int main(int argc, char **argv) { struct timeval now_time; bool copyover = false; gettimeofday(&now_time, NULL); current_time = (time_t) now_time.tv_sec; str_boot_time = ctime(¤t_time); if(argc > 1) { if(!is_num(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]) { copyover = true; control = atoi(argv[3]); } else copyover = false; } if(!copyover) control = init_socket(port); startup(); init_signals(); if(copyover) copyover_recover(); game_loop(control); close(control); log_string("Normal termination of game."); exit(0); return 0; } int init_socket(int port) { static struct sockaddr_in sa_zero; struct sockaddr_in sa; int x = 1, fd; if((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("init_socket: socket"); exit(1); } if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &x, sizeof(x)) < 0) { perror("init_socket: SO_REUSEADDR"); close(fd); exit(1); } sa = sa_zero; sa.sin_family = AF_INET; sa.sin_port = htons(port); if(bind(fd, (struct sockaddr *) &sa, sizeof(sa) ) < 0) { perror("Init socket: bind"); close(fd); exit(1); } if(listen(fd, 3) < 0) { perror("Init socket: listen"); close(fd); exit(1); } return fd; } void game_loop(int control) { static struct timeval null_time; struct timeval last_time; DESC *d_next; signal(SIGPIPE, SIG_IGN); gettimeofday(&last_time, NULL); current_time = (time_t) last_time.tv_sec; while(!game_down) { fd_set in_set, out_set, exc_set; DESC *d; int maxdesc; FD_ZERO(&in_set); FD_ZERO(&out_set); FD_ZERO(&exc_set); FD_SET(control, &in_set); maxdesc = control; for(d = desc_list; d; d = d->next) { maxdesc = UMAX(maxdesc, d->desc); FD_SET(d->desc, &in_set); FD_SET(d->desc, &out_set); FD_SET(d->desc, &exc_set); } if(select(maxdesc + 1, &in_set, &out_set, &exc_set, &null_time) < 0) { perror("gameLoop: select: poll"); exit(1); } if(FD_ISSET(control, &in_set)) init_descriptor(control); FD_ZERO(&in_set); FD_ZERO(&out_set); FD_ZERO(&exc_set); for(d = desc_list; d; d = d->next) { maxdesc = UMAX(maxdesc, d->desc); FD_SET(d->desc, &in_set); FD_SET(d->desc, &out_set); FD_SET(d->desc, &exc_set); } if(select(maxdesc + 1, &in_set, &out_set, &exc_set, &null_time) < 0) { perror("gameLoop: select: poll"); exit(1); } for(d = desc_list; d; d = d_next) { d_next = d->next; if(FD_ISSET(d->desc, &exc_set)) { FD_CLR(d->desc, &in_set); FD_CLR(d->desc, &out_set); if(d->ch && d->connected == CON_PLAYING) d->ch->save(); d->outbuf = ""; d->close_socket(); } } for(d = desc_list; d; d = d_next) { d_next = d->next; d->fcommand = false; if(FD_ISSET(d->desc, &in_set)) { if(d->ch) d->ch->timer = 0; if(!d->read()) { FD_CLR(d->desc, &out_set); if(d->ch && d->connected == CON_PLAYING) d->ch->save(); d->outbuf = ""; d->close_socket(); continue; } } if(d->ch && d->connected == CON_GET_NAME && ++d->ch->timer == 60) { d->ch->printf("Idle timeout, disconnecting...\n\r"); d->close_socket(); continue; } if(d->ch && d->ch->wait) { --d->ch->wait; continue; } d->read_buffer(); if(!d->incomm.empty()) { d->fcommand = true; switch(d->connected) { case CON_PLAYING: if(!d->ch->queue[0].empty()) d->ch->update_queue(); else d->ch->interpret(d->incomm); break; default: d->nanny(d->incomm); break; } d->incomm = ""; } } update_handler(); for(d = desc_list; d; d = d_next) { d_next = d->next; if((d->fcommand || !d->outbuf.empty()) && FD_ISSET(d->desc, &out_set)) { if(!d->process_output(true)) { if(d->ch) d->ch->save(); d->outbuf = ""; d->close_socket(); } } } { struct timeval now_time; long secDelta, usecDelta; gettimeofday(&now_time, NULL); usecDelta = ((int) last_time.tv_usec) - ((int) now_time.tv_usec) + 1000000 / PPS; 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) { perror("gameLoop: select: stall"); exit(1); } } } gettimeofday(&last_time, NULL); current_time = (time_t) last_time.tv_sec; } return; } void init_descriptor(int control) { DESC *dnew = new DESC; struct sockaddr_in sock; struct hostent *from; int desc, size; size = sizeof(sock); getsockname(control, (struct sockaddr *) &sock, (socklen_t *) &size); if((desc = accept(control, (struct sockaddr *) &sock, (socklen_t *)&size)) < 0) { perror("New_descriptor: accept"); return; } #if !defined(FNDELAY) #define FNDELAY O_NDELAY #endif if(fcntl(desc, F_SETFL, FNDELAY) == -1) { perror("New_descriptor: fcntl: FNDELAY"); return; } dnew->desc = desc; dnew->connected = CON_GET_NAME; size = sizeof(sock); if(getpeername(desc, (struct sockaddr *) &sock, (socklen_t *) &size) < 0) { perror("New_descriptor: getpeername"); dnew->host = "(unknown)"; } else { int addr = ntohl(sock.sin_addr.s_addr); ostrstream ost; ost << ((addr >> 24) & 0xFF) << '.' << ((addr >> 16) & 0xFF) << '.' << ((addr >> 8) & 0xFF) << '.' << ((addr) & 0xFF) << ends; from = gethostbyaddr((char *) &sock.sin_addr, sizeof(sock.sin_addr), AF_INET); dnew->host = (from ? from->h_name : ost.str()); wiz_echo(dnew->host + " has connected.\n\r"); log_string("Sock.sinaddr: " + dnew->host + " (" + ost.str() + ")"); } dnew->printf(login_screen); dnew->printf("Name: "); return; } void save_players() { log_string("Saving players..."); for(CH *ch = ch_list; ch; ch = ch->next) ch->save(); return; } void tell_all(int sig) { switch(sig) { case SIGBUS: log_string("SIGBUS (Bus Error"); break; case SIGTERM: log_string("SIGTERM (Term signal)"); break; case SIGSEGV: log_string("SIGSEG (Invalid memory Reference)"); break; case SIGILL: log_string("SIGILL (Illegal instruction)"); break; case SIGFPE: log_string("SIGFPE (Floating Point Error)"); break; case SIGHUP: log_string("SIGHUP (Hangup Signal)"); break; default: log_string("Unhandled Signal."); break; } signal(sig, SIG_DFL); log_string("Last command: " + lcom); log_string("ERROR: Game has crashed!"); // do_copyover(NULL, "auto"); // save_players(); return; } void init_signals() { signal(SIGBUS, tell_all); signal(SIGTERM, tell_all); signal(SIGFPE, tell_all); signal(SIGILL, tell_all); signal(SIGSEGV, tell_all); signal(SIGHUP, tell_all); signal(SIGSTOP, tell_all); signal(SIGKILL, tell_all); signal(6, tell_all); return; } void bug(const string str) { string str_bug = "[*****] BUG: " + str; log_string(str_bug); return; }