/* ================== SV_KickNum_f Kick a user off of the server FIXME: move to game ================== */ static void SV_KickNum_f( void ) { client_t *cl; // make sure server is running if ( !com_sv_running->integer ) { Com_Printf( "Server is not running.\n" ); return; } if ( Cmd_Argc() != 2 ) { Com_Printf ("Usage: kicknum <client number>\n"); return; } cl = SV_GetPlayerByNum(); if ( !cl ) { return; } if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) { // SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n"); SV_SendServerCommand(NULL, "print \"%s\"", SV_GetStripEdString("SVINGAME","CANNOT_KICK_HOST")); return; } SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" ); cl->lastPacketTime = svs.time; // in case there is a funny zombie }
static void SV_KickByName( const char *name ) { client_t *cl; int i; // make sure server is running if ( !com_sv_running->integer ) { return; } cl = SV_GetPlayerByFedName(name); if ( !cl ) { if ( !Q_stricmp(name, "all") ) { for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) { if ( !cl->state ) { continue; } if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) { continue; } SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" ); cl->lastPacketTime = svs.time; // in case there is a funny zombie } } else if ( !Q_stricmp(name, "allbots") ) { for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) { if ( !cl->state ) { continue; } if( cl->netchan.remoteAddress.type != NA_BOT ) { continue; } SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" ); cl->lastPacketTime = svs.time; // in case there is a funny zombie } } return; } if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) { // SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n"); SV_SendServerCommand(NULL, "print \"%s\"", SV_GetStripEdString("SVINGAME","CANNOT_KICK_HOST")); return; } SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" ); cl->lastPacketTime = svs.time; // in case there is a funny zombie }
/* ================== SV_Kick_f Kick a user off of the server FIXME: move to game ================== */ static void SV_Kick_f( void ) { client_t *cl; int i; // make sure server is running if ( !com_sv_running->integer ) { Com_Printf( "Server is not running.\n" ); return; } if ( Cmd_Argc() != 2 ) { Com_Printf ("Usage: kick <player name>\nkick all = kick everyone\nkick allbots = kick all bots\n"); return; } if (!Q_stricmp(Cmd_Argv(1), "Padawan")) { //if you try to kick the default name, also try to kick "" SV_KickByName(""); } cl = SV_GetPlayerByName(); if ( !cl ) { if ( !Q_stricmp(Cmd_Argv(1), "all") ) { for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) { if ( !cl->state ) { continue; } if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) { continue; } SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" ); cl->lastPacketTime = svs.time; // in case there is a funny zombie } } else if ( !Q_stricmp(Cmd_Argv(1), "allbots") ) { for ( i=0, cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++ ) { if ( !cl->state ) { continue; } if( cl->netchan.remoteAddress.type != NA_BOT ) { continue; } SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" ); cl->lastPacketTime = svs.time; // in case there is a funny zombie } } return; } if( cl->netchan.remoteAddress.type == NA_LOOPBACK ) { // SV_SendServerCommand(NULL, "print \"%s\"", "Cannot kick host player\n"); SV_SendServerCommand(NULL, "print \"%s\"", SV_GetStripEdString("SVINGAME","CANNOT_KICK_HOST")); return; } SV_DropClient( cl, SV_GetStripEdString("SVINGAME","WAS_KICKED")); // "was kicked" ); cl->lastPacketTime = svs.time; // in case there is a funny zombie }
/* ================== SV_DirectConnect A "connect" OOB command has been received ================== */ void SV_DirectConnect( netadr_t from ) { char userinfo[MAX_INFO_STRING]; int i; client_t *cl, *newcl; MAC_STATIC client_t temp; sharedEntity_t *ent; int clientNum; int version; int qport; int challenge; char *password; int startIndex; char *denied; int count; Com_DPrintf ("SVC_DirectConnect ()\n"); Q_strncpyz( userinfo, Cmd_Argv(1), sizeof(userinfo) ); version = atoi( Info_ValueForKey( userinfo, "protocol" ) ); if ( version != PROTOCOL_VERSION ) { NET_OutOfBandPrint( NS_SERVER, from, "print\nServer uses protocol version %i.\n", PROTOCOL_VERSION ); Com_DPrintf (" rejected connect from version %i\n", version); return; } challenge = atoi( Info_ValueForKey( userinfo, "challenge" ) ); qport = atoi( Info_ValueForKey( userinfo, "qport" ) ); // quick reject for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) { if ( cl->state == CS_FREE ) { continue; } if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) && ( cl->netchan.qport == qport || from.port == cl->netchan.remoteAddress.port ) ) { if (( svs.time - cl->lastConnectTime) < (sv_reconnectlimit->integer * 1000)) { Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (from)); return; } break; } } // see if the challenge is valid (LAN clients don't need to challenge) if ( !NET_IsLocalAddress (from) ) { int ping; for (i=0 ; i<MAX_CHALLENGES ; i++) { if (NET_CompareAdr(from, svs.challenges[i].adr)) { if ( challenge == svs.challenges[i].challenge ) { break; // good } } } if (i == MAX_CHALLENGES) { NET_OutOfBandPrint( NS_SERVER, from, "print\nNo or bad challenge for address.\n" ); return; } // force the IP key/value pair so the game can filter based on ip Info_SetValueForKey( userinfo, "ip", NET_AdrToString( from ) ); ping = svs.time - svs.challenges[i].pingTime; Com_Printf( "Client %i connecting with %i challenge ping\n", i, ping ); svs.challenges[i].connected = qtrue; // never reject a LAN client based on ping if ( !Sys_IsLANAddress( from ) ) { if ( sv_minPing->value && ping < sv_minPing->value ) { // don't let them keep trying until they get a big delay NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for high pings only\n" ); Com_DPrintf ("Client %i rejected on a too low ping\n", i); // reset the address otherwise their ping will keep increasing // with each connect message and they'd eventually be able to connect svs.challenges[i].adr.port = 0; return; } if ( sv_maxPing->value && ping > sv_maxPing->value ) { NET_OutOfBandPrint( NS_SERVER, from, "print\nServer is for low pings only\n" ); Com_DPrintf ("Client %i rejected on a too high ping\n", i); return; } } } else { // force the "ip" info key to "localhost" Info_SetValueForKey( userinfo, "ip", "localhost" ); } newcl = &temp; Com_Memset (newcl, 0, sizeof(client_t)); // if there is already a slot for this ip, reuse it for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) { if ( cl->state == CS_FREE ) { continue; } if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) && ( cl->netchan.qport == qport || from.port == cl->netchan.remoteAddress.port ) ) { Com_Printf ("%s:reconnect\n", NET_AdrToString (from)); newcl = cl; // disconnect the client from the game first so any flags the // player might have are dropped VM_Call( gvm, GAME_CLIENT_DISCONNECT, newcl - svs.clients ); // goto gotnewcl; } } // find a client slot // if "sv_privateClients" is set > 0, then that number // of client slots will be reserved for connections that // have "password" set to the value of "sv_privatePassword" // Info requests will report the maxclients as if the private // slots didn't exist, to prevent people from trying to connect // to a full server. // This is to allow us to reserve a couple slots here on our // servers so we can play without having to kick people. // check for privateClient password password = Info_ValueForKey( userinfo, "password" ); if ( !strcmp( password, sv_privatePassword->string ) ) { startIndex = 0; } else { // skip past the reserved slots startIndex = sv_privateClients->integer; } newcl = NULL; for ( i = startIndex; i < sv_maxclients->integer ; i++ ) { cl = &svs.clients[i]; if (cl->state == CS_FREE) { newcl = cl; break; } } if ( !newcl ) { if ( NET_IsLocalAddress( from ) ) { count = 0; for ( i = startIndex; i < sv_maxclients->integer ; i++ ) { cl = &svs.clients[i]; if (cl->netchan.remoteAddress.type == NA_BOT) { count++; } } // if they're all bots if (count >= sv_maxclients->integer - startIndex) { SV_DropClient(&svs.clients[sv_maxclients->integer - 1], "only bots on server"); newcl = &svs.clients[sv_maxclients->integer - 1]; } else { Com_Error( ERR_FATAL, "server is full on local connect\n" ); return; } } else { const char *SV_GetStripEdString(char *refSection, char *refName); NET_OutOfBandPrint( NS_SERVER, from, va("print\n%s\n", SV_GetStripEdString("SVINGAME","SERVER_IS_FULL"))); Com_DPrintf ("Rejected a connection.\n"); return; } } // we got a newcl, so reset the reliableSequence and reliableAcknowledge cl->reliableAcknowledge = 0; cl->reliableSequence = 0; gotnewcl: // build a new connection // accept the new client // this is the only place a client_t is ever initialized *newcl = temp; clientNum = newcl - svs.clients; ent = SV_GentityNum( clientNum ); newcl->gentity = ent; // save the challenge newcl->challenge = challenge; // save the address Netchan_Setup (NS_SERVER, &newcl->netchan , from, qport); // save the userinfo Q_strncpyz( newcl->userinfo, userinfo, sizeof(newcl->userinfo) ); // get the game a chance to reject this connection or modify the userinfo denied = (char *)VM_Call( gvm, GAME_CLIENT_CONNECT, clientNum, qtrue, qfalse ); // firstTime = qtrue if ( denied ) { // we can't just use VM_ArgPtr, because that is only valid inside a VM_Call denied = (char *)VM_ExplicitArgPtr( gvm, (int)denied ); NET_OutOfBandPrint( NS_SERVER, from, "print\n%s\n", denied ); Com_DPrintf ("Game rejected a connection: %s.\n", denied); return; } SV_UserinfoChanged( newcl ); // send the connect packet to the client NET_OutOfBandPrint( NS_SERVER, from, "connectResponse" ); Com_DPrintf( "Going from CS_FREE to CS_CONNECTED for %s\n", newcl->name ); newcl->state = CS_CONNECTED; newcl->nextSnapshotTime = svs.time; newcl->lastPacketTime = svs.time; newcl->lastConnectTime = svs.time; // when we receive the first packet from the client, we will // notice that it is from a different serverid and that the // gamestate message was not just sent, forcing a retransmit newcl->gamestateMessageNum = -1; // if this was the first client on the server, or the last client // the server can hold, send a heartbeat to the master. count = 0; for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) { if ( svs.clients[i].state >= CS_CONNECTED ) { count++; } } if ( count == 1 || count == sv_maxclients->integer ) { SV_Heartbeat_f(); } }
static void SV_Disconnect_f( client_t *cl ) { // SV_DropClient( cl, "disconnected" ); SV_DropClient( cl, SV_GetStripEdString("SVINGAME","DISCONNECTED") ); }