Annotation of quake2/server/sv_main.c, revision 1.1.1.3

1.1       root        1: 
                      2: #include "server.h"
                      3: 
                      4: netadr_t       master_adr[MAX_MASTERS];        // address of group servers
                      5: 
                      6: client_t       *sv_client;                     // current client
                      7: 
                      8: cvar_t *sv_paused;
                      9: cvar_t *sv_timedemo;
                     10: 
                     11: cvar_t *sv_enforcetime;
                     12: 
                     13: cvar_t *timeout;                               // seconds without any message
                     14: cvar_t *zombietime;                    // seconds to sink messages after disconnect
                     15: 
                     16: cvar_t *rcon_password;                 // password for remote server commands
                     17: 
                     18: cvar_t *allow_download;
1.1.1.2   root       19: cvar_t *allow_download_players;
                     20: cvar_t *allow_download_models;
                     21: cvar_t *allow_download_sounds;
                     22: cvar_t *allow_download_maps;
1.1       root       23: 
1.1.1.3 ! root       24: cvar_t *sv_airaccelerate;
        !            25: 
1.1       root       26: cvar_t *sv_noreload;                   // don't reload level state when reentering
                     27: 
                     28: cvar_t *maxclients;                    // FIXME: rename sv_maxclients
                     29: cvar_t *sv_showclamp;
                     30: 
                     31: cvar_t *hostname;
                     32: cvar_t *public_server;                 // should heartbeats be sent
                     33: 
                     34: cvar_t *sv_reconnect_limit;    // minimum seconds between connect messages
                     35: 
                     36: void Master_Shutdown (void);
                     37: 
                     38: 
                     39: //============================================================================
                     40: 
                     41: 
                     42: /*
                     43: =====================
                     44: SV_DropClient
                     45: 
                     46: Called when the player is totally leaving the server, either willingly
                     47: or unwillingly.  This is NOT called if the entire server is quiting
                     48: or crashing.
                     49: =====================
                     50: */
                     51: void SV_DropClient (client_t *drop)
                     52: {
                     53:        // add the disconnect
                     54:        MSG_WriteByte (&drop->netchan.message, svc_disconnect);
                     55: 
                     56:        if (drop->state == cs_spawned)
                     57:        {
                     58:                // call the prog function for removing a client
                     59:                // this will remove the body, among other things
                     60:                ge->ClientDisconnect (drop->edict);
                     61:        }
                     62: 
                     63:        if (drop->download)
                     64:        {
                     65:                FS_FreeFile (drop->download);
                     66:                drop->download = NULL;
                     67:        }
                     68: 
                     69:        drop->state = cs_zombie;                // become free in a few seconds
                     70:        drop->name[0] = 0;
                     71: }
                     72: 
                     73: 
                     74: 
                     75: /*
                     76: ==============================================================================
                     77: 
                     78: CONNECTIONLESS COMMANDS
                     79: 
                     80: ==============================================================================
                     81: */
                     82: 
                     83: /*
                     84: ===============
                     85: SV_StatusString
                     86: 
                     87: Builds the string that is sent as heartbeats and status replies
                     88: ===============
                     89: */
                     90: char   *SV_StatusString (void)
                     91: {
                     92:        char    player[1024];
1.1.1.3 ! root       93:        static char     status[MAX_MSGLEN - 16];
1.1       root       94:        int             i;
                     95:        client_t        *cl;
                     96:        int             statusLength;
                     97:        int             playerLength;
                     98: 
                     99:        strcpy (status, Cvar_Serverinfo());
                    100:        strcat (status, "\n");
                    101:        statusLength = strlen(status);
                    102: 
                    103:        for (i=0 ; i<maxclients->value ; i++)
                    104:        {
                    105:                cl = &svs.clients[i];
                    106:                if (cl->state == cs_connected || cl->state == cs_spawned )
                    107:                {
                    108:                        Com_sprintf (player, sizeof(player), "%i %i \"%s\"\n", 
                    109:                                cl->edict->client->ps.stats[STAT_FRAGS], cl->ping, cl->name);
                    110:                        playerLength = strlen(player);
                    111:                        if (statusLength + playerLength >= sizeof(status) )
                    112:                                break;          // can't hold any more
                    113:                        strcpy (status + statusLength, player);
                    114:                        statusLength += playerLength;
                    115:                }
                    116:        }
                    117: 
                    118:        return status;
                    119: }
                    120: 
                    121: /*
                    122: ================
                    123: SVC_Status
                    124: 
                    125: Responds with all the info that qplug or qspy can see
                    126: ================
                    127: */
                    128: void SVC_Status (void)
                    129: {
1.1.1.3 ! root      130:        Netchan_OutOfBandPrint (NS_SERVER, net_from, "print\n%s", SV_StatusString());
        !           131: #if 0
1.1       root      132:        Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
                    133:        Com_Printf (SV_StatusString());
                    134:        Com_EndRedirect ();
1.1.1.3 ! root      135: #endif
1.1       root      136: }
                    137: 
                    138: /*
                    139: ================
                    140: SVC_Ack
                    141: 
                    142: ================
                    143: */
                    144: void SVC_Ack (void)
                    145: {
                    146:        Com_Printf ("Ping acknowledge from %s\n", NET_AdrToString(net_from));
                    147: }
                    148: 
                    149: /*
                    150: ================
                    151: SVC_Info
                    152: 
                    153: Responds with short info for broadcast scans
                    154: The second parameter should be the current protocol version number.
                    155: ================
                    156: */
                    157: void SVC_Info (void)
                    158: {
                    159:        char    string[64];
                    160:        int             i, count;
                    161:        int             version;
                    162: 
                    163:        if (maxclients->value == 1)
                    164:                return;         // ignore in single player
                    165: 
                    166:        version = atoi (Cmd_Argv(1));
                    167: 
                    168:        if (version != PROTOCOL_VERSION)
                    169:                Com_sprintf (string, sizeof(string), "%s: wrong version\n", hostname->string, sizeof(string));
                    170:        else
                    171:        {
                    172:                count = 0;
                    173:                for (i=0 ; i<maxclients->value ; i++)
                    174:                        if (svs.clients[i].state >= cs_connected)
                    175:                                count++;
                    176: 
                    177:                Com_sprintf (string, sizeof(string), "%16s %8s %2i/%2i\n", hostname->string, sv.name, count, (int)maxclients->value);
                    178:        }
                    179: 
                    180:        Netchan_OutOfBandPrint (NS_SERVER, net_from, "info\n%s", string);
                    181: }
                    182: 
                    183: /*
                    184: ================
                    185: SVC_Ping
                    186: 
                    187: Just responds with an acknowledgement
                    188: ================
                    189: */
                    190: void SVC_Ping (void)
                    191: {
                    192:        Netchan_OutOfBandPrint (NS_SERVER, net_from, "ack");
                    193: }
                    194: 
                    195: 
                    196: /*
                    197: =================
                    198: SVC_GetChallenge
                    199: 
                    200: Returns a challenge number that can be used
                    201: in a subsequent client_connect command.
                    202: We do this to prevent denial of service attacks that
                    203: flood the server with invalid connection IPs.  With a
                    204: challenge, they must give a valid IP address.
                    205: =================
                    206: */
                    207: void SVC_GetChallenge (void)
                    208: {
                    209:        int             i;
                    210:        int             oldest;
                    211:        int             oldestTime;
                    212: 
                    213:        oldest = 0;
                    214:        oldestTime = 0x7fffffff;
                    215: 
                    216:        // see if we already have a challenge for this ip
                    217:        for (i = 0 ; i < MAX_CHALLENGES ; i++)
                    218:        {
                    219:                if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
                    220:                        break;
                    221:                if (svs.challenges[i].time < oldestTime)
                    222:                {
                    223:                        oldestTime = svs.challenges[i].time;
                    224:                        oldest = i;
                    225:                }
                    226:        }
                    227: 
                    228:        if (i == MAX_CHALLENGES)
                    229:        {
                    230:                // overwrite the oldest
1.1.1.2   root      231:                svs.challenges[oldest].challenge = rand() & 0x7fff;
1.1       root      232:                svs.challenges[oldest].adr = net_from;
                    233:                svs.challenges[oldest].time = curtime;
                    234:                i = oldest;
                    235:        }
                    236: 
                    237:        // send it back
                    238:        Netchan_OutOfBandPrint (NS_SERVER, net_from, "challenge %i", svs.challenges[i].challenge);
                    239: }
                    240: 
                    241: /*
                    242: ==================
                    243: SVC_DirectConnect
                    244: 
                    245: A connection request that did not come from the master
                    246: ==================
                    247: */
                    248: void SVC_DirectConnect (void)
                    249: {
                    250:        char            userinfo[MAX_INFO_STRING];
                    251:        netadr_t        adr;
                    252:        int                     i;
                    253:        client_t        *cl, *newcl;
                    254:        client_t        temp;
                    255:        edict_t         *ent;
                    256:        int                     edictnum;
                    257:        int                     version;
                    258:        int                     qport;
                    259:        int                     challenge;
                    260: 
                    261:        adr = net_from;
                    262: 
                    263:        Com_DPrintf ("SVC_DirectConnect ()\n");
                    264: 
                    265:        version = atoi(Cmd_Argv(1));
                    266:        if (version != PROTOCOL_VERSION)
                    267:        {
                    268:                Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is version %4.2f.\n", VERSION);
                    269:                Com_DPrintf ("    rejected connect from version %i\n", version);
                    270:                return;
                    271:        }
                    272: 
                    273:        qport = atoi(Cmd_Argv(2));
                    274: 
                    275:        challenge = atoi(Cmd_Argv(3));
                    276: 
                    277:        strncpy (userinfo, Cmd_Argv(4), sizeof(userinfo)-1);
1.1.1.2   root      278:        userinfo[sizeof(userinfo) - 1] = 0;
1.1       root      279: 
                    280:        // force the IP key/value pair so the game can filter based on ip
                    281:        Info_SetValueForKey (userinfo, "ip", NET_AdrToString(net_from));
                    282: 
                    283:        // attractloop servers are ONLY for local clients
                    284:        if (sv.attractloop)
                    285:        {
                    286:                if (!NET_IsLocalAddress (adr))
                    287:                {
                    288:                        Com_Printf ("Remote connect in attract loop.  Ignored.\n");
                    289:                        Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n");
                    290:                        return;
                    291:                }
                    292:        }
                    293: 
                    294:        // see if the challenge is valid
                    295:        if (!NET_IsLocalAddress (adr))
                    296:        {
                    297:                for (i=0 ; i<MAX_CHALLENGES ; i++)
                    298:                {
                    299:                        if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr))
                    300:                        {
                    301:                                if (challenge == svs.challenges[i].challenge)
                    302:                                        break;          // good
                    303:                                Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nBad challenge.\n");
                    304:                                return;
                    305:                        }
                    306:                }
                    307:                if (i == MAX_CHALLENGES)
                    308:                {
                    309:                        Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nNo challenge for address.\n");
                    310:                        return;
                    311:                }
                    312:        }
                    313: 
                    314:        newcl = &temp;
                    315:        memset (newcl, 0, sizeof(client_t));
                    316: 
                    317:        // if there is already a slot for this ip, reuse it
                    318:        for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
                    319:        {
                    320:                if (cl->state == cs_free)
                    321:                        continue;
                    322:                if (NET_CompareBaseAdr (adr, cl->netchan.remote_address)
                    323:                        && ( cl->netchan.qport == qport 
                    324:                        || adr.port == cl->netchan.remote_address.port ) )
                    325:                {
1.1.1.2   root      326:                        if (!NET_IsLocalAddress (adr) && (svs.realtime - cl->lastconnect) < ((int)sv_reconnect_limit->value * 1000))
1.1       root      327:                        {
                    328:                                Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (adr));
                    329:                                return;
                    330:                        }
                    331:                        Com_Printf ("%s:reconnect\n", NET_AdrToString (adr));
                    332:                        newcl = cl;
                    333:                        goto gotnewcl;
                    334:                }
                    335:        }
                    336: 
                    337:        // find a client slot
                    338:        newcl = NULL;
                    339:        for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
                    340:        {
                    341:                if (cl->state == cs_free)
                    342:                {
                    343:                        newcl = cl;
                    344:                        break;
                    345:                }
                    346:        }
                    347:        if (!newcl)
                    348:        {
                    349:                Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nServer is full.\n");
                    350:                Com_DPrintf ("Rejected a connection.\n");
                    351:                return;
                    352:        }
                    353: 
                    354: gotnewcl:      
                    355:        // build a new connection
                    356:        // accept the new client
                    357:        // this is the only place a client_t is ever initialized
                    358:        *newcl = temp;
                    359:        sv_client = newcl;
                    360:        edictnum = (newcl-svs.clients)+1;
                    361:        ent = EDICT_NUM(edictnum);
                    362:        newcl->edict = ent;
1.1.1.2   root      363:        newcl->challenge = challenge; // save challenge for checksumming
1.1       root      364: 
                    365:        // get the game a chance to reject this connection or modify the userinfo
                    366:        if (!(ge->ClientConnect (ent, userinfo)))
                    367:        {
1.1.1.3 ! root      368:                if (*Info_ValueForKey (userinfo, "rejmsg")) 
        !           369:                        Netchan_OutOfBandPrint (NS_SERVER, adr, "print\n%s\nConnection refused.\n",  
        !           370:                                Info_ValueForKey (userinfo, "rejmsg"));
        !           371:                else
        !           372:                        Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n" );
1.1       root      373:                Com_DPrintf ("Game rejected a connection.\n");
                    374:                return;
                    375:        }
                    376: 
                    377:        // parse some info from the info strings
                    378:        strncpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)-1);
                    379:        SV_UserinfoChanged (newcl);
                    380: 
                    381:        // send the connect packet to the client
                    382:        Netchan_OutOfBandPrint (NS_SERVER, adr, "client_connect");
                    383: 
                    384:        Netchan_Setup (NS_SERVER, &newcl->netchan , adr, qport);
                    385: 
                    386:        newcl->state = cs_connected;
                    387:        
                    388:        SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf) );
                    389:        newcl->datagram.allowoverflow = true;
                    390:        newcl->lastmessage = svs.realtime;      // don't timeout
                    391:        newcl->lastconnect = svs.realtime;
                    392: }
                    393: 
                    394: int Rcon_Validate (void)
                    395: {
                    396:        if (!strlen (rcon_password->string))
                    397:                return 0;
                    398: 
                    399:        if (strcmp (Cmd_Argv(1), rcon_password->string) )
                    400:                return 0;
                    401: 
                    402:        return 1;
                    403: }
                    404: 
                    405: /*
                    406: ===============
                    407: SVC_RemoteCommand
                    408: 
                    409: A client issued an rcon command.
                    410: Shift down the remaining args
                    411: Redirect all printfs
                    412: ===============
                    413: */
                    414: void SVC_RemoteCommand (void)
                    415: {
                    416:        int             i;
                    417:        char    remaining[1024];
                    418: 
                    419:        i = Rcon_Validate ();
                    420: 
                    421:        if (i == 0)
                    422:                Com_Printf ("Bad rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
1.1.1.2   root      423:        else
1.1       root      424:                Com_Printf ("Rcon from %s:\n%s\n", NET_AdrToString (net_from), net_message.data+4);
                    425: 
                    426:        Com_BeginRedirect (RD_PACKET, sv_outputbuf, SV_OUTPUTBUF_LENGTH, SV_FlushRedirect);
                    427: 
                    428:        if (!Rcon_Validate ())
                    429:        {
                    430:                Com_Printf ("Bad rcon_password.\n");
                    431:        }
                    432:        else
                    433:        {
                    434:                remaining[0] = 0;
                    435: 
                    436:                for (i=2 ; i<Cmd_Argc() ; i++)
                    437:                {
                    438:                        strcat (remaining, Cmd_Argv(i) );
                    439:                        strcat (remaining, " ");
                    440:                }
                    441: 
                    442:                Cmd_ExecuteString (remaining);
                    443:        }
                    444: 
                    445:        Com_EndRedirect ();
                    446: }
                    447: 
                    448: /*
                    449: =================
                    450: SV_ConnectionlessPacket
                    451: 
                    452: A connectionless packet has four leading 0xff
                    453: characters to distinguish it from a game channel.
                    454: Clients that are in the game can still send
                    455: connectionless packets.
                    456: =================
                    457: */
                    458: void SV_ConnectionlessPacket (void)
                    459: {
                    460:        char    *s;
                    461:        char    *c;
                    462: 
                    463:        MSG_BeginReading (&net_message);
                    464:        MSG_ReadLong (&net_message);            // skip the -1 marker
                    465: 
                    466:        s = MSG_ReadStringLine (&net_message);
                    467: 
                    468:        Cmd_TokenizeString (s, false);
                    469: 
                    470:        c = Cmd_Argv(0);
                    471:        Com_DPrintf ("Packet %s : %s\n", NET_AdrToString(net_from), c);
                    472: 
                    473:        if (!strcmp(c, "ping"))
                    474:                SVC_Ping ();
                    475:        else if (!strcmp(c, "ack"))
                    476:                SVC_Ack ();
                    477:        else if (!strcmp(c,"status"))
                    478:                SVC_Status ();
                    479:        else if (!strcmp(c,"info"))
                    480:                SVC_Info ();
                    481:        else if (!strcmp(c,"getchallenge"))
                    482:                SVC_GetChallenge ();
                    483:        else if (!strcmp(c,"connect"))
                    484:                SVC_DirectConnect ();
                    485:        else if (!strcmp(c, "rcon"))
                    486:                SVC_RemoteCommand ();
                    487:        else
                    488:                Com_Printf ("bad connectionless packet from %s:\n%s\n"
                    489:                , NET_AdrToString (net_from), s);
                    490: }
                    491: 
                    492: 
                    493: //============================================================================
                    494: 
                    495: /*
                    496: ===================
                    497: SV_CalcPings
                    498: 
                    499: Updates the cl->ping variables
                    500: ===================
                    501: */
                    502: void SV_CalcPings (void)
                    503: {
                    504:        int                     i, j;
                    505:        client_t        *cl;
                    506:        int                     total, count;
                    507: 
                    508:        for (i=0 ; i<maxclients->value ; i++)
                    509:        {
                    510:                cl = &svs.clients[i];
                    511:                if (cl->state != cs_spawned )
                    512:                        continue;
                    513: 
1.1.1.2   root      514: #if 0
1.1       root      515:                if (cl->lastframe > 0)
                    516:                        cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = sv.framenum - cl->lastframe + 1;
                    517:                else
                    518:                        cl->frame_latency[sv.framenum&(LATENCY_COUNTS-1)] = 0;
1.1.1.2   root      519: #endif
1.1       root      520: 
                    521:                total = 0;
                    522:                count = 0;
                    523:                for (j=0 ; j<LATENCY_COUNTS ; j++)
                    524:                {
                    525:                        if (cl->frame_latency[j] > 0)
                    526:                        {
                    527:                                count++;
                    528:                                total += cl->frame_latency[j];
                    529:                        }
                    530:                }
                    531:                if (!count)
                    532:                        cl->ping = 0;
                    533:                else
1.1.1.2   root      534: #if 0
1.1       root      535:                        cl->ping = total*100/count - 100;
1.1.1.2   root      536: #else
                    537:                        cl->ping = total / count;
                    538: #endif
1.1       root      539: 
                    540:                // let the game dll know about the ping
                    541:                cl->edict->client->ping = cl->ping;
                    542:        }
                    543: }
                    544: 
                    545: 
                    546: /*
                    547: ===================
                    548: SV_GiveMsec
                    549: 
                    550: Every few frames, gives all clients an allotment of milliseconds
                    551: for their command moves.  If they exceed it, assume cheating.
                    552: ===================
                    553: */
                    554: void SV_GiveMsec (void)
                    555: {
                    556:        int                     i;
                    557:        client_t        *cl;
                    558: 
                    559:        if (sv.framenum & 15)
                    560:                return;
                    561: 
                    562:        for (i=0 ; i<maxclients->value ; i++)
                    563:        {
                    564:                cl = &svs.clients[i];
                    565:                if (cl->state == cs_free )
                    566:                        continue;
                    567:                
                    568:                cl->commandMsec = 1800;         // 1600 + some slop
                    569:        }
                    570: }
                    571: 
                    572: 
                    573: /*
                    574: =================
                    575: SV_ReadPackets
                    576: =================
                    577: */
                    578: void SV_ReadPackets (void)
                    579: {
                    580:        int                     i;
                    581:        client_t        *cl;
                    582:        int                     qport;
                    583: 
                    584:        while (NET_GetPacket (NS_SERVER, &net_from, &net_message))
                    585:        {
                    586:                // check for connectionless packet (0xffffffff) first
                    587:                if (*(int *)net_message.data == -1)
                    588:                {
                    589:                        SV_ConnectionlessPacket ();
                    590:                        continue;
                    591:                }
                    592: 
                    593:                // read the qport out of the message so we can fix up
                    594:                // stupid address translating routers
                    595:                MSG_BeginReading (&net_message);
                    596:                MSG_ReadLong (&net_message);            // sequence number
                    597:                MSG_ReadLong (&net_message);            // sequence number
                    598:                qport = MSG_ReadShort (&net_message) & 0xffff;
                    599: 
                    600:                // check for packets from connected clients
                    601:                for (i=0, cl=svs.clients ; i<maxclients->value ; i++,cl++)
                    602:                {
                    603:                        if (cl->state == cs_free)
                    604:                                continue;
                    605:                        if (!NET_CompareBaseAdr (net_from, cl->netchan.remote_address))
                    606:                                continue;
                    607:                        if (cl->netchan.qport != qport)
                    608:                                continue;
                    609:                        if (cl->netchan.remote_address.port != net_from.port)
                    610:                        {
                    611:                                Com_Printf ("SV_ReadPackets: fixing up a translated port\n");
                    612:                                cl->netchan.remote_address.port = net_from.port;
                    613:                        }
                    614: 
                    615:                        if (Netchan_Process(&cl->netchan, &net_message))
                    616:                        {       // this is a valid, sequenced packet, so process it
                    617:                                if (cl->state != cs_zombie)
                    618:                                {
                    619:                                        cl->lastmessage = svs.realtime; // don't timeout
                    620:                                        SV_ExecuteClientMessage (cl);
                    621:                                }
                    622:                        }
                    623:                        break;
                    624:                }
                    625:                
                    626:                if (i != maxclients->value)
                    627:                        continue;
                    628:        }
                    629: }
                    630: 
                    631: /*
                    632: ==================
                    633: SV_CheckTimeouts
                    634: 
                    635: If a packet has not been received from a client for timeout->value
                    636: seconds, drop the conneciton.  Server frames are used instead of
                    637: realtime to avoid dropping the local client while debugging.
                    638: 
                    639: When a client is normally dropped, the client_t goes into a zombie state
                    640: for a few seconds to make sure any final reliable message gets resent
                    641: if necessary
                    642: ==================
                    643: */
                    644: void SV_CheckTimeouts (void)
                    645: {
                    646:        int             i;
                    647:        client_t        *cl;
                    648:        int                     droppoint;
                    649:        int                     zombiepoint;
                    650: 
                    651:        droppoint = svs.realtime - 1000*timeout->value;
                    652:        zombiepoint = svs.realtime - 1000*zombietime->value;
                    653: 
                    654:        for (i=0,cl=svs.clients ; i<maxclients->value ; i++,cl++)
                    655:        {
                    656:                // message times may be wrong across a changelevel
                    657:                if (cl->lastmessage > svs.realtime)
                    658:                        cl->lastmessage = svs.realtime;
                    659: 
                    660:                if (cl->state == cs_zombie
                    661:                && cl->lastmessage < zombiepoint)
                    662:                {
                    663:                        cl->state = cs_free;    // can now be reused
                    664:                        continue;
                    665:                }
                    666:                if ( (cl->state == cs_connected || cl->state == cs_spawned) 
                    667:                        && cl->lastmessage < droppoint)
                    668:                {
                    669:                        SV_BroadcastPrintf (PRINT_HIGH, "%s timed out\n", cl->name);
                    670:                        SV_DropClient (cl); 
                    671:                        cl->state = cs_free;    // don't bother with zombie state
                    672:                }
                    673:        }
                    674: }
                    675: 
                    676: /*
                    677: ================
                    678: SV_PrepWorldFrame
                    679: 
                    680: This has to be done before the world logic, because
                    681: player processing happens outside RunWorldFrame
                    682: ================
                    683: */
                    684: void SV_PrepWorldFrame (void)
                    685: {
                    686:        edict_t *ent;
                    687:        int             i;
                    688: 
                    689:        for (i=0 ; i<ge->num_edicts ; i++, ent++)
                    690:        {
                    691:                ent = EDICT_NUM(i);
                    692:                // events only last for a single message
                    693:                ent->s.event = 0;
                    694:        }
                    695: 
                    696: }
                    697: 
                    698: 
                    699: /*
                    700: =================
                    701: SV_RunGameFrame
                    702: =================
                    703: */
                    704: void SV_RunGameFrame (void)
                    705: {
                    706:        if (host_speeds->value)
                    707:                time_before_game = Sys_Milliseconds ();
                    708: 
                    709:        // we always need to bump framenum, even if we
                    710:        // don't run the world, otherwise the delta
                    711:        // compression can get confused when a client
                    712:        // has the "current" frame
                    713:        sv.framenum++;
                    714:        sv.time = sv.framenum*100;
                    715: 
                    716:        // don't run if paused
                    717:        if (!sv_paused->value || maxclients->value > 1)
                    718:        {
                    719:                ge->RunFrame ();
                    720: 
                    721:                // never get more than one tic behind
                    722:                if (sv.time < svs.realtime)
                    723:                {
                    724:                        if (sv_showclamp->value)
                    725:                                Com_Printf ("sv highclamp\n");
                    726:                        svs.realtime = sv.time;
                    727:                }
                    728:        }
                    729: 
                    730:        if (host_speeds->value)
                    731:                time_after_game = Sys_Milliseconds ();
                    732: 
                    733: }
                    734: 
                    735: /*
                    736: ==================
                    737: SV_Frame
                    738: 
                    739: ==================
                    740: */
                    741: void SV_Frame (int msec)
                    742: {
                    743:        time_before_game = time_after_game = 0;
                    744: 
                    745:        // if server is not active, do nothing
                    746:        if (!svs.initialized)
                    747:                return;
                    748: 
                    749:     svs.realtime += msec;
                    750: 
                    751:        // keep the random time dependent
                    752:        rand ();
                    753: 
                    754:        // check timeouts
                    755:        SV_CheckTimeouts ();
                    756: 
                    757:        // get packets from clients
                    758:        SV_ReadPackets ();
                    759: 
                    760:        // move autonomous things around if enough time has passed
                    761:        if (!sv_timedemo->value && svs.realtime < sv.time)
                    762:        {
                    763:                // never let the time get too far off
                    764:                if (sv.time - svs.realtime > 100)
                    765:                {
                    766:                        if (sv_showclamp->value)
                    767:                                Com_Printf ("sv lowclamp\n");
                    768:                        svs.realtime = sv.time - 100;
                    769:                }
1.1.1.2   root      770:                NET_Sleep(sv.time - svs.realtime);
1.1       root      771:                return;
                    772:        }
                    773: 
                    774:        // update ping based on the last known frame from all clients
                    775:        SV_CalcPings ();
                    776: 
                    777:        // give the clients some timeslices
                    778:        SV_GiveMsec ();
                    779: 
                    780:        // let everything in the world think and move
                    781:        SV_RunGameFrame ();
                    782: 
                    783:        // send messages back to the clients that had packets read this frame
                    784:        SV_SendClientMessages ();
                    785: 
                    786:        // save the entire world state if recording a serverdemo
                    787:        SV_RecordDemoMessage ();
                    788: 
                    789:        // send a heartbeat to the master if needed
                    790:        Master_Heartbeat ();
                    791: 
                    792:        // clear teleport flags, etc for next frame
                    793:        SV_PrepWorldFrame ();
                    794: 
                    795: }
                    796: 
                    797: //============================================================================
                    798: 
                    799: /*
                    800: ================
                    801: Master_Heartbeat
                    802: 
                    803: Send a message to the master every few minutes to
                    804: let it know we are alive, and log information
                    805: ================
                    806: */
                    807: #define        HEARTBEAT_SECONDS       300
                    808: void Master_Heartbeat (void)
                    809: {
                    810:        char            *string;
                    811:        int                     i;
                    812: 
                    813:        
                    814:        if (!dedicated->value)
                    815:                return;         // only dedicated servers send heartbeats
                    816: 
                    817:        if (!public_server->value)
                    818:                return;         // a private dedicated game
                    819: 
                    820:        // check for time wraparound
                    821:        if (svs.last_heartbeat > svs.realtime)
                    822:                svs.last_heartbeat = svs.realtime;
                    823: 
                    824:        if (svs.realtime - svs.last_heartbeat < HEARTBEAT_SECONDS*1000)
                    825:                return;         // not time to send yet
                    826: 
                    827:        svs.last_heartbeat = svs.realtime;
                    828: 
                    829:        // send the same string that we would give for a status OOB command
                    830:        string = SV_StatusString();
                    831: 
                    832:        // send to group master
                    833:        for (i=0 ; i<MAX_MASTERS ; i++)
                    834:                if (master_adr[i].port)
                    835:                {
                    836:                        Com_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
                    837:                        Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "heartbeat\n%s", string);
                    838:                }
                    839: }
                    840: 
                    841: /*
                    842: =================
                    843: Master_Shutdown
                    844: 
                    845: Informs all masters that this server is going down
                    846: =================
                    847: */
                    848: void Master_Shutdown (void)
                    849: {
                    850:        int                     i;
                    851: 
                    852:        if (!dedicated->value)
                    853:                return;         // only dedicated servers send heartbeats
                    854: 
                    855:        if (!public_server->value)
                    856:                return;         // a private dedicated game
                    857: 
                    858:        // send to group master
                    859:        for (i=0 ; i<MAX_MASTERS ; i++)
                    860:                if (master_adr[i].port)
                    861:                {
                    862:                        if (i > 0)
                    863:                                Com_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i]));
                    864:                        Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "shutdown");
                    865:                }
                    866: }
                    867: 
                    868: //============================================================================
                    869: 
                    870: 
                    871: /*
                    872: =================
                    873: SV_UserinfoChanged
                    874: 
                    875: Pull specific info from a newly changed userinfo string
                    876: into a more C freindly form.
                    877: =================
                    878: */
                    879: void SV_UserinfoChanged (client_t *cl)
                    880: {
                    881:        char    *val;
                    882:        int             i;
                    883: 
                    884:        // call prog code to allow overrides
                    885:        ge->ClientUserinfoChanged (cl->edict, cl->userinfo);
                    886:        
                    887:        // name for C code
                    888:        strncpy (cl->name, Info_ValueForKey (cl->userinfo, "name"), sizeof(cl->name)-1);
                    889:        // mask off high bit
                    890:        for (i=0 ; i<sizeof(cl->name) ; i++)
                    891:                cl->name[i] &= 127;
                    892: 
                    893:        // rate command
                    894:        val = Info_ValueForKey (cl->userinfo, "rate");
                    895:        if (strlen(val))
                    896:        {
                    897:                i = atoi(val);
                    898:                cl->rate = i;
                    899:                if (cl->rate < 100)
                    900:                        cl->rate = 100;
                    901:                if (cl->rate > 15000)
                    902:                        cl->rate = 15000;
                    903:        }
                    904:        else
                    905:                cl->rate = 5000;
                    906: 
                    907:        // msg command
                    908:        val = Info_ValueForKey (cl->userinfo, "msg");
                    909:        if (strlen(val))
                    910:        {
                    911:                cl->messagelevel = atoi(val);
                    912:        }
                    913: 
                    914: }
                    915: 
                    916: 
                    917: //============================================================================
                    918: 
                    919: /*
                    920: ===============
                    921: SV_Init
                    922: 
                    923: Only called at quake2.exe startup, not for each game
                    924: ===============
                    925: */
                    926: void SV_Init (void)
                    927: {
                    928:        SV_InitOperatorCommands ();
                    929: 
                    930:        rcon_password = Cvar_Get ("rcon_password", "", 0);
                    931:        Cvar_Get ("skill", "1", 0);
                    932:        Cvar_Get ("deathmatch", "0", CVAR_LATCH);
                    933:        Cvar_Get ("coop", "0", CVAR_LATCH);
                    934:        Cvar_Get ("dmflags", va("%i", DF_INSTANT_ITEMS), CVAR_SERVERINFO);
                    935:        Cvar_Get ("fraglimit", "0", CVAR_SERVERINFO);
                    936:        Cvar_Get ("timelimit", "0", CVAR_SERVERINFO);
                    937:        Cvar_Get ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
                    938:        Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO|CVAR_NOSET);;
                    939:        maxclients = Cvar_Get ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH);
                    940:        hostname = Cvar_Get ("hostname", "noname", CVAR_SERVERINFO | CVAR_ARCHIVE);
                    941:        timeout = Cvar_Get ("timeout", "125", 0);
                    942:        zombietime = Cvar_Get ("zombietime", "2", 0);
                    943:        sv_showclamp = Cvar_Get ("showclamp", "0", 0);
                    944:        sv_paused = Cvar_Get ("paused", "0", 0);
                    945:        sv_timedemo = Cvar_Get ("timedemo", "0", 0);
                    946:        sv_enforcetime = Cvar_Get ("sv_enforcetime", "0", 0);
1.1.1.2   root      947:        allow_download = Cvar_Get ("allow_download", "0", CVAR_ARCHIVE);
                    948:        allow_download_players  = Cvar_Get ("allow_download_players", "0", CVAR_ARCHIVE);
                    949:        allow_download_models = Cvar_Get ("allow_download_models", "1", CVAR_ARCHIVE);
                    950:        allow_download_sounds = Cvar_Get ("allow_download_sounds", "1", CVAR_ARCHIVE);
                    951:        allow_download_maps       = Cvar_Get ("allow_download_maps", "1", CVAR_ARCHIVE);
                    952: 
1.1       root      953:        sv_noreload = Cvar_Get ("sv_noreload", "0", 0);
                    954: 
1.1.1.3 ! root      955:        sv_airaccelerate = Cvar_Get("sv_airaccelerate", "0", CVAR_LATCH);
        !           956: 
1.1       root      957:        public_server = Cvar_Get ("public", "0", 0);
                    958: 
                    959:        sv_reconnect_limit = Cvar_Get ("sv_reconnect_limit", "3", CVAR_ARCHIVE);
                    960: 
                    961:        SZ_Init (&net_message, net_message_buffer, sizeof(net_message_buffer));
                    962: }
                    963: 
                    964: /*
                    965: ==================
                    966: SV_FinalMessage
                    967: 
                    968: Used by SV_Shutdown to send a final message to all
                    969: connected clients before the server goes down.  The messages are sent immediately,
                    970: not just stuck on the outgoing message list, because the server is going
                    971: to totally exit after returning from this function.
                    972: ==================
                    973: */
                    974: void SV_FinalMessage (char *message, qboolean reconnect)
                    975: {
                    976:        int                     i;
                    977:        client_t        *cl;
                    978:        
                    979:        SZ_Clear (&net_message);
                    980:        MSG_WriteByte (&net_message, svc_print);
                    981:        MSG_WriteByte (&net_message, PRINT_HIGH);
                    982:        MSG_WriteString (&net_message, message);
                    983: 
                    984:        if (reconnect)
                    985:                MSG_WriteByte (&net_message, svc_reconnect);
                    986:        else
                    987:                MSG_WriteByte (&net_message, svc_disconnect);
                    988: 
                    989:        // send it twice
                    990:        // stagger the packets to crutch operating system limited buffers
                    991: 
                    992:        for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
                    993:                if (cl->state >= cs_connected)
                    994:                        Netchan_Transmit (&cl->netchan, net_message.cursize
                    995:                        , net_message.data);
                    996: 
                    997:        for (i=0, cl = svs.clients ; i<maxclients->value ; i++, cl++)
                    998:                if (cl->state >= cs_connected)
                    999:                        Netchan_Transmit (&cl->netchan, net_message.cursize
                   1000:                        , net_message.data);
                   1001: }
                   1002: 
                   1003: 
                   1004: 
                   1005: /*
                   1006: ================
                   1007: SV_Shutdown
                   1008: 
                   1009: Called when each game quits,
                   1010: before Sys_Quit or Sys_Error
                   1011: ================
                   1012: */
                   1013: void SV_Shutdown (char *finalmsg, qboolean reconnect)
                   1014: {
                   1015:        if (svs.clients)
                   1016:                SV_FinalMessage (finalmsg, reconnect);
                   1017: 
                   1018:        Master_Shutdown ();
                   1019:        SV_ShutdownGameProgs ();
                   1020: 
                   1021:        // free current level
                   1022:        if (sv.demofile)
                   1023:                fclose (sv.demofile);
                   1024:        memset (&sv, 0, sizeof(sv));
                   1025:        Com_SetServerState (sv.state);
                   1026: 
                   1027:        // free server static data
                   1028:        if (svs.clients)
                   1029:                Z_Free (svs.clients);
                   1030:        if (svs.client_entities)
                   1031:                Z_Free (svs.client_entities);
                   1032:        if (svs.demofile)
                   1033:                fclose (svs.demofile);
                   1034:        memset (&svs, 0, sizeof(svs));
                   1035: }
                   1036: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.