home *** CD-ROM | disk | FTP | other *** search
- /* server.c */
- /*
-
- * Copyright 1994 A.Oliver De Guzman
- * All rights reserved
-
- * Permission is granted to any individual to copy, use, and/or
- * distribute this software provided that the distribution retains this
- * entire copyright notice. No part of this software may be used and/or
- * sold for profit or used with any commercial product.
-
- * DISCLAIMER:
- * This software comes with NO WARRANTIES of any kind. In no event
- * will the author be liable for any financial, physical, moral, and/or
- * mental damages incurred directly or indirectly by the use or intent
- * to use of this software.
-
- */
-
- #define DEBUG
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <setjmp.h>
- #include <signal.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include "dfcss.h"
- #include "sock.h"
- #include "node.h"
- #include "config.h"
- #include "log.h"
-
- #define CONFIGFILE "server.cfg"
- #define EMAILLEN 30
- #define NAMELEN 20
- #define ALIASLEN 12
- #define WAITASEC 5
- #define DEFAULT_DELAY 60
-
- #define printIP(str, peer) sprintf(str, "%d.%d.%d.%d",\
- (htonl(peer.sin_addr.s_addr) >> 24) & 0xFF,\
- (htonl(peer.sin_addr.s_addr) >> 16) & 0xFF,\
- (htonl(peer.sin_addr.s_addr) >> 8) & 0xFF,\
- (htonl(peer.sin_addr.s_addr) ) & 0xFF)
-
-
- char slog[1024];
- int sd, newfd = -1;
- char banner[MAXMSG+1];
- int port = PORT_NUMBER;
- jmp_buf mainloop;
- FILE *fp;
- int timeron=0;
-
- char MESSAGEFILE[128] = "server.msg";
- char SERVERLIST[128] = "server.lst";
- Config sconfigs[] = {
- { "msgfile", CFG_STR, MESSAGEFILE },
- { "serverlist", CFG_STR, SERVERLIST },
- };
- #define SNUMCONFIGS (sizeof(sconfigs)/sizeof(Config))
-
- char NAME[128] = "", EMAIL[128] = "", ALIAS[128];
- Config cconfigs[] = {
- { "name", CFG_STR, NAME },
- { "alias", CFG_STR, ALIAS },
- { "email", CFG_STR, EMAIL },
- };
- #define CNUMCONFIGS (sizeof(cconfigs)/sizeof(Config))
-
- /*char COMMAND[1024] = "tcpsetup";*/
- char MODE[128] = "-deathmatch";
- int PORT = 0x869c;
- int SKILL = 4;
- int EPISODE = 1;
- int MISSION = 1;
- int TIMER = 0;
- char MONSTERS[128] = "";
- char WADFILES[1024] = "";
- char EXTENSIONS[1024] = "";
-
- int DELAY = DEFAULT_DELAY;
- int NUMPLAYERS = 3;
- Config configs[] = {
- /* { "command", CFG_STR, COMMAND }, */
- { "mode", CFG_STR, MODE },
- { "port", CFG_INT, &PORT },
- { "skill", CFG_INT, &SKILL },
- { "episode", CFG_INT, &EPISODE },
- { "mission", CFG_INT, &MISSION },
- { "timer", CFG_INT, &TIMER },
- { "monsters", CFG_STR, MONSTERS },
- { "wadfiles", CFG_STR, WADFILES },
- { "extensions", CFG_STR, EXTENSIONS },
- { "delay", CFG_INT, &DELAY },
- { "numplayers", CFG_INT, &NUMPLAYERS }
- };
- #define NUMCONFIGS (sizeof(configs)/sizeof(Config))
-
- char sethelp[] =
- "\n\
- * Help on setting game parameters\n\
- * Type \"/set <parameter> <value>\" where <parameter> is any of:\n\
- * mode [-deathmatch|-altdeath] regular deathmatch or deathmatch v2.0\n\
- * port <portnum> port number to use, 0=do not use -port\n\
- * skill [0-5] skill level, 0=do not use -skill\n\
- * episode [0-3] episode number, 0 for DOOM2\n\
- * mission [1-9] mission number, 1-32 if episode=0\n\
- * timer <minutes> time, 0=do not use -timer\n\
- * monsters [-nomonsters|-respawn|-fast] monster behavior\n\
- * wadfiles [first.wad [second.wad ...]] wadfiles to use\n\
- * extensions <string> put undocumented params here\n\
- * delay <seconds> delay before starting the game\n\
- * numplayers [2-4] number of players";
-
- void HelpSet()
- {
- ASockWrite(nodes[nodeidx].sd, sethelp);
-
- }
-
- char *PlayStat()
- {
- static char msg[MAXMSG+1];
- char buff[128];;
-
- sprintf(msg, "* Current Setting:");
- sprintf(buff, "\n* Number of Players:%2d Delay: %4d second(s)", NUMPLAYERS, DELAY); strcat(msg, buff);
- sprintf(buff, "\n* Skill:%2d Port: 0x%X", SKILL, PORT); strcat(msg, buff);
- sprintf(buff, "\n* Episode:%2d Mission:%2d", EPISODE, MISSION); strcat(msg, buff);
- sprintf(buff, "\n* Mode: %s %*sMonsters: %s", MODE, 18-strlen(MODE), " ", MONSTERS); strcat(msg, buff);
- sprintf(buff, "\n* Wadfiles: %s", WADFILES); strcat(msg, buff);
- sprintf(buff, "\n* Extensions: %s", EXTENSIONS); strcat(msg, buff);
- sprintf(buff, "\n* Timer: %d minute(s)", TIMER); strcat(msg, buff);
- return(msg);
- }
-
-
- int CheckSettings()
- {
- StripWhite(MODE);
- if (strcmp(MODE, "-deathmatch") && strcmp(MODE, "-altdeath") && MODE[0])
- MODE[0] = '\0';
- SKILL = MAX(0, MIN(SKILL, 5));
- EPISODE = MAX(0, MIN(EPISODE, 3));
- if (EPISODE) MISSION = MAX(1, MIN(MISSION, 9));
- else MISSION = MAX(1, MIN(MISSION, 32));
-
- TIMER = MAX(0, MIN(TIMER, 60*48)); /* Max of 2 days play time :) */
- StripWhite(MONSTERS);
- if (strcmp(MONSTERS, "-nomonsters") && strcmp(MONSTERS, "-respawn")
- && strcmp(MONSTERS, "-fast") && MONSTERS[0])
- MONSTERS[0] = '\0';
- /* WADFILES not checked */
- StripWhite(WADFILES);
- StripWhite(EXTENSIONS);
-
- DELAY = MAX(0, MIN(DELAY, 60*60)); /* Max delay of 1 hour */
- NUMPLAYERS = MAX(2, MIN(NUMPLAYERS, 4)); /* 2-4 players */
- }
-
- void Shutdown()
- {
- int i;
-
- sprintf(slog, "%d shutdown", port); logger(fp, slog);
- #ifdef DEBUG
- printf("\nServer_ShutDown.\n");
- #endif
-
- WriteNodes(ABORT);
- for (i=0; i<MAX_NODES; i++){
- if (!IsUnused(nodes[i]))
- close(nodes[i].sd);
- }
-
- close(sd);
- closelog(fp);
- exit(3);
- }
-
- void Ignore()
- {
- #ifdef DEBUG
- printf("Ignore");
- #endif
- signal(SIGPIPE, Ignore);
- }
-
- void ResetNode()
- {
- #ifdef DEBUG
- printf("ResetNode[%d]", nodeidx);
- #endif
- if (newfd != -1) close(newfd);
- signal(SIGPIPE, ResetNode);
- longjmp(mainloop, 1);
- }
-
- void ResetServer()
- {
- #ifdef DEBUG
- printf("ResetServer");
- #endif
- logger(fp, "ResetServer");
- signal(SIGPIPE, ResetServer);
- longjmp(mainloop, 2);
- }
-
- int setfds(rfds)
- fd_set *rfds;
- {
- int i;
- int maxfd = 0;
-
- FD_ZERO(rfds);
- FD_SET(sd, rfds);
- maxfd = sd;
-
- for (i=0; i<MAX_NODES; i++){
- if (!IsUnused(nodes[i])){
- FD_SET(nodes[i].sd, rfds);
- if (nodes[i].sd > maxfd)
- maxfd = nodes[i].sd;
- }
- }
-
- return(maxfd+1);
- }
-
-
- int helpme(sd)
- int sd;
- {
- ASockWrite(sd, "* type /help for commands");
- }
-
-
- #define SET "set"
-
- int ExecuteCommand(cmd)
- char cmd[];
- {
- char buff[MAXMSG+1], *msg;
- int n;
-
- StripWhite(cmd);
- msg = cmd;
- if (DoCommand(nodeidx, msg) < 0){
- int ch;
-
- msg++;
- ch = msg[strlen(SET)];
- msg[strlen(SET)] = '\0';
- if (!strcmp(SET, msg)){
- msg[strlen(SET)] = ch;
- if (strlen(msg+strlen(SET)) > 0){
- if (IsPlayer(nodes[nodeidx]) || IsGod(nodes[nodeidx])){
- if ((n = configline(msg+strlen(SET)+1, configs, NUMCONFIGS)) >= 0 && n < NUMCONFIGS){
- CheckSettings();
- sprintf(buff, "#%s> %s", nodes[nodeidx].alias, msg);
- WriteNodes(buff);
- }
- else{
- strcpy(buff, "* type /help set");
- ASockWrite(nodes[nodeidx].sd, buff);
- }
- }
- else ASockWrite(nodes[nodeidx].sd,
- "! Cannot use /set <var> <value> while in guest mode.");
- }
- else{
- sprintf(buff, "%s", PlayStat());
- ASockWrite(nodes[nodeidx].sd, buff);
- }
- }
- else helpme(nodes[nodeidx].sd);
- }
- }
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- char msg[MAXMSG+1], msg2[MAXMSG+1];
- char commandline[MAXMSG+1];
- struct sockaddr_in peer;
- int peersize = sizeof(peer);
- char IPstr[4*4+10];
- fd_set rfds, trfds;
- struct timeval tv;
- int maxfd;
- int i, j;
- char configfile[1024];
- char tmpfname[1024], serverlog[1024];
- int type = PLAYER;
- int idx, playernum;
-
- strcpy(configfile, CONFIGFILE);
- if ((i = CheckParm("-nodes", argc, argv)) && (i < argc-1))
- NUMPLAYERS = MIN(MAX_PLAYERS, atoi(argv[i+1]));
-
- if ((i = CheckParm("-port", argc, argv)) && (i < argc-1))
- port = atoi(argv[i+1]);
-
- sprintf(serverlog, "%d.log", port);
- if ((i = CheckParm("-log", argc, argv)) && (i < argc-1))
- strcpy(serverlog, argv[i+1]);
-
- if ((i = CheckParm("-config", argc, argv)) && (i < argc-1))
- strcpy(configfile, argv[i+1]);
-
- fp = openlog(serverlog);
- sprintf(slog, "%d start %d nodes", port, NUMPLAYERS);
- logger(fp, slog);
-
- /* Read the Filenames */
- if (readconfig(configfile, sconfigs, SNUMCONFIGS) < 0){
- #ifdef DEBUG
- printf("Cannot open config file [%s]. Using defaults.\n", configfile);
- #endif
- }
-
- /* Read Initial Settings */
- readconfig(configfile, configs, NUMCONFIGS);
- CheckSettings();
-
- StripWhite(MESSAGEFILE);
- StripWhite(SERVERLIST);
-
- #ifdef DEBUG
- printf("Listener_Start[%d] on port [0x%x]\n", NUMPLAYERS, port);
- #endif
- sd = SockOpen(NULL, port);
- if (sd == -1) exit(2);
-
- sprintf(tmpfname, "%d.tmp", port);
- signal(SIGPIPE, ResetNode);
- signal(SIGINT, Shutdown);
- InitNodes();
- switch (setjmp(mainloop)){
- case 2:
- case 1:
- if (nodeidx != -1){
- sprintf(slog, "%d reset node %d", port, nodeidx);
- logger(fp, slog);
- sprintf(msg, "! %s %s left.",
- StrNodeType(nodes[nodeidx].type), NodeStat(nodeidx));
-
- close(nodes[nodeidx].sd);
- InitNode(nodeidx);
- WriteNodes(msg);
- }
- case 0:
- while (1){
-
- #ifdef DEBUG
- printf("\nListener_Listen[%d] port[%d]...", NumPlayers(), port);
- fflush(stdout);
- #endif
-
- while (NumPlayers() < NUMPLAYERS || (DELAY > 0)){
-
- /* select timeout interval */
- tv.tv_sec = 1;
-
- /* wait for and then accept a connect request */
- if (listen(sd, 5) == -1){
- perror("Listener: listen failed");
- continue;
- }
-
- maxfd = setfds(&rfds);
- trfds = rfds;
- if (select(maxfd, &trfds, NULL, NULL, &tv) < 0){
- perror("Listener: select");
- ResetServer();
- }
-
- if (FD_ISSET(sd, &trfds)){
- if ((newfd = accept(sd, NULL, NULL)) == -1){
- perror("Listener: accept failed");
- continue;
- }
- }
- else{
- /* Check if any sd is ready for read/write */
- for (i=0; i<MAX_NODES; i++){
- if (!IsUnused(nodes[i]) && FD_ISSET(nodes[i].sd, &trfds)){
- nodeidx = i;
- ASockRead(nodes[nodeidx].sd, msg);
-
- if (msg[0] == '/'){
- ExecuteCommand(msg);
- }
- else {
- sprintf(msg2, "#%s> %s", nodes[i].alias, msg);
- WriteNodes(msg2);
- }
- }
- }
-
- #ifdef DEBUG
- printf("."); fflush(stdout);
- #endif
-
- if (NumPlayers() == NUMPLAYERS){
- if (!timeron) WriteNodes("* Number of Players Satisfied. Starting delay timer.\n* Type \"/set delay <seconds>\" to shorten/lenghten delay.");
- DELAY--;
- if (DELAY==10 || DELAY==30 || DELAY==45){
- sprintf(msg, "* %d seconds delay left", DELAY);
- WriteNodes(msg);
- }
- timeron = 1;
- }
- else if (timeron){
- WriteNodes("* Stoping delay timer.");
- timeron = 0;
- }
-
- continue;
- }
-
- getpeername(newfd, (struct sockaddr *)&peer, &peersize);
- printIP(IPstr, peer);
- if (!strcmp(IPstr, "127.0.0.1")){
- getsockname(newfd, (struct sockaddr *)&peer, &peersize);
- printIP(IPstr, peer);
- }
- #ifdef DEBUG
- printf("connect[%s].\n", IPstr); fflush(stdout);
- #endif
-
- nodeidx = -1;
- idx = NewNodeIndex();
- sprintf(slog, "%d node %d %s", port, idx, IPstr);
- logger(fp, slog);
-
- #ifdef DEBUG
- printf("Listener_WriteServerID[%d]...", idx); fflush(stdout);
- #endif
- SockWrite(newfd, SERVERID, IDLEN);
- #ifdef DEBUG
- printf("done.\n");
-
- printf("Listener_ReadNodeType..."); fflush(stdout);
- #endif
- ASockRead(newfd, msg);
- type = GetNodeType(msg);
- #ifdef DEBUG
- printf("done[%d].\n", type);
- printf("Listener_ReadOptions[%s]...", msg); fflush(stdout);
- #endif
- if (type == STATUS){
- #ifdef DEBUG
- printf("Status Connection..."); fflush(stdout);
- #endif
- ServerStat(newfd);
- sprintf(slog, "%d %s %d", port, StrNodeType(type), idx);
- logger(fp, slog);
- #ifdef DEBUG
- printf("serviced.\n");
- #endif
- longjmp(mainloop, 0);
- }
-
- /* read options from client */
- ASockRead(newfd, msg);
-
- /* set variables from read msg */
- writefile(tmpfname, msg, strlen(msg));
- readconfig(tmpfname, cconfigs, CNUMCONFIGS);
- if (NumPlayers() == 0){
- readconfig(tmpfname, configs, NUMCONFIGS);
- CheckSettings();
- }
- #ifdef DEBUG
- printf("done.\n");
- #endif
-
- StripWhite(EMAIL);
- StripWhite(NAME); NAME[NAMELEN] = '\0';
- StripWhite(ALIAS); ALIAS[ALIASLEN] = '\0';
- sprintf(slog, "%d %s %d %s %s %s",
- port, StrNodeType(type), idx, EMAIL, ALIAS, NAME);
- logger(fp, slog);
-
- #ifdef DEBUG
- printf("Read_MessageFile:[%s]\n", MESSAGEFILE); fflush(stdout);
- #endif
- if (readfile(MESSAGEFILE, banner, MAXMSG) < 0)
- sprintf(banner, "The Generic Frag Server\n");
-
- #ifdef DEBUG
- printf("done.\n");
- printf("Sending Server Stat...");
- #endif
- ASockWrite(newfd, banner);
- ServerStat(newfd);
- if (type == PLAYER && NumPlayers()==NUMPLAYERS){
- type = GUEST;
- ASockWrite(newfd, "* No place for a player, switching to guest.\n* Type /player to join a game.");
- }
-
- if (type == GOD && NumGods()==MAX_GODS){
- type = GUEST;
- ASockWrite(newfd, "* Too many gods.");
- }
-
- idx = NewNode(type, newfd, NAME, EMAIL, ALIAS, IPstr);
- if (idx < 0){
- ASockWrite(newfd, "! Sorry. No more room for another victim.");
- ResetNode();
- }
- else {
- sprintf(msg, "+ %s %s connected.", StrNodeType(type),
- NodeStat(idx));
- WriteNodes(msg);
- helpme(newfd);
- }
-
- #ifdef DEBUG
- printf("done.\n");
- printf("Listener_Listen[%d] port[%d]...", NumPlayers(), port);
- fflush(stdout);
- #endif
- newfd = -1;
- } /* end of while */
-
- sprintf(msg, "\n%s\n%s\n* Prepare to meet you DOOM!\n* Waiting for another %d seconds....",
- PlayersStat(), PlayStat(), WAITASEC);
- WriteNodes(msg);
- sleep(WAITASEC);
-
- DELAY = DEFAULT_DELAY;
-
- commandline[0] = '\0';
-
- /* coop, deathmatch or altdeath */
- if (strlen(MODE) > 0){
- strcat(commandline, MODE);
- strcat(commandline, "\n");
- }
-
- /* skill level */
- if (SKILL){
- sprintf(msg, "-skill %d\n", SKILL);
- strcat(commandline, msg);
- }
-
- /* episode and mission number */
- if (EPISODE) sprintf(msg, "-warp %d %d\n", EPISODE, MISSION);
- else sprintf(msg, "-warp %d\n", MISSION);
- strcat(commandline, msg);
-
- /* monsters */
- if (strlen(MONSTERS) > 0){
- strcat(commandline, MONSTERS);
- strcat(commandline, "\n");
- }
-
- /* wadfiles */
- if (strlen(WADFILES) > 0){
- sprintf(msg, "-file %s\n", WADFILES);
- strcat(commandline, msg);
- }
-
- /* timer */
- if (TIMER){
- sprintf(msg, "-timer %d\n", TIMER);
- strcat(commandline, msg);
- }
-
- /* port number */
- if (PORT > 0){
- sprintf(msg, "-port %d\n", PORT);
- strcat(commandline, msg);
- }
-
- signal(SIGPIPE, ResetServer);
- sprintf(slog, "%d play %d", port, NumPlayers());
- for (nodeidx=0, playernum=0; nodeidx<MAX_NODES; nodeidx++){
-
- if (IsPlayer(nodes[nodeidx])){
- playernum++;
- ASockWrite(nodes[nodeidx].sd, CONNECT);
-
- sprintf(msg2, "");
- if (strlen(EXTENSIONS))
- sprintf(msg, "%s -net %d ", EXTENSIONS, playernum);
- else
- sprintf(msg, "-net %d ", playernum);
-
- for (j=0; j<MAX_NODES; j++){
- if ((nodeidx != j) && IsPlayer(nodes[j])){
- strcat(msg2, NodeStat(j));
-
- strcat(msg, nodes[j].ip);
- strcat(msg, " ");
- }
- }
-
- /* write out the someting for the client's log */
- StripWhite(msg2);
- ASockWrite(nodes[nodeidx].sd, msg2);
-
- /* write the parameters for the response file */
- ASockWrite(nodes[nodeidx].sd, commandline);
-
- /* send the commandline parameters to node[nodeidx] */
- StripWhite(msg);
- ASockWrite(nodes[nodeidx].sd, msg);
-
- strcat(slog, " ");
- strcat(slog, IPstr);
- }
- }
-
- logger(fp, slog);
-
- signal(SIGPIPE, Ignore);
- sprintf(msg, "\n* Go.");
- for (i=0; i<MAX_NODES; i++){
- if (IsPlayer(nodes[i])){
- ASockWrite(nodes[i].sd, msg);
- close(nodes[i].sd);
- InitNode(i);
- }
- }
-
- #ifdef DEBUG
- printf("%d nodes Connected.\n", NUMPLAYERS);
- #endif
- sprintf(msg, "\n* %d nodes Connected.\n", NUMPLAYERS);
- WriteNodes(msg);
- signal(SIGPIPE, ResetNode);
-
- }
- break;
- default:
- break;
- } /* end of switch */
- }
-
-