/* ================== SV_SetInfo_f Allow clients to change userinfo ================== */ static void SV_SetInfo_f (void) { if (Cmd_Argc() == 1) { Con_Printf ("User info settings:\n"); Info_Print (host_client->userinfo); return; } if (Cmd_Argc() != 3) { Con_Printf ("usage: setinfo [ <key> <value> ]\n"); return; } if (Cmd_Argv(1)[0] == '*') return; // don't set priveledged values Info_SetValueForKey (host_client->userinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_INFO_STRING); q_strlcpy (host_client->name, Info_ValueForKey (host_client->userinfo, "name"), sizeof(host_client->name)); // SV_FullClientUpdate (host_client, &sv.reliable_datagram); host_client->sendinfo = true; // process any changed values SV_ExtractFromUserinfo (host_client); }
void SV_SetInfo_f (void) { int i; char oldval[MAX_INFO_STRING]; if (Cmd_Argc() == 1) { Con_Printf ("User info settings:\n"); Info_Print (host_client->userinfo); return; } if (Cmd_Argc() != 3) { Con_Printf ("usage: setinfo [ <key> <value> ]\n"); return; } if (Cmd_Argv(1)[0] == '*') return; // don't set priveledged values strcpy(oldval, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1))); Info_SetValueForKey (host_client->userinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_INFO_STRING); // name is extracted below in ExtractFromUserInfo // strncpy (host_client->name, Info_ValueForKey (host_client->userinfo, "name") // , sizeof(host_client->name)-1); // SV_FullClientUpdate (host_client, &sv.reliable_datagram); // host_client->sendinfo = true; if (!strcmp(Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)), oldval)) return; // key hasn't changed // process any changed values SV_ExtractFromUserinfo (host_client); i = host_client - svs.clients; MSG_WriteByte (&sv.reliable_datagram, svc_setinfo); MSG_WriteByte (&sv.reliable_datagram, i); MSG_WriteString (&sv.reliable_datagram, Cmd_Argv(1)); MSG_WriteString (&sv.reliable_datagram, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1))); }
/* ================== SVC_DirectConnect A connection request that did not come from the master ================== */ void SVC_DirectConnect (void) { char userinfo[1024]; netadr_t adr; int i; client_t *cl, *newcl; edict_t *ent; int edictnum; char *s; int clients, spectators; qbool spectator; int qport; int version; int challenge; version = atoi(Cmd_Argv(1)); if (version != PROTOCOL_VERSION) { Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nServer is version %4.2f.\n", A2C_PRINT, QW_VERSION); Com_Printf ("* rejected connect from version %i\n", version); return; } qport = atoi(Cmd_Argv(2)); challenge = atoi(Cmd_Argv(3)); // note an extra byte is needed to replace spectator key strlcpy (userinfo, Cmd_Argv(4), sizeof(userinfo)-1); // see if the challenge is valid if (net_from.type != NA_LOOPBACK) { for (i=0 ; i<MAX_CHALLENGES ; i++) { if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr)) { if (challenge == svs.challenges[i].challenge) break; // good Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nBad challenge.\n", A2C_PRINT); return; } } if (i == MAX_CHALLENGES) { Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nNo challenge for address.\n", A2C_PRINT); return; } } // check for password or spectator_password s = Info_ValueForKey (userinfo, "spectator"); if (s[0] && strcmp(s, "0")) { if (sv_spectatorPassword.string[0] && Q_stricmp(sv_spectatorPassword.string, "none") && strcmp(sv_spectatorPassword.string, s) ) { // failed Com_Printf ("%s:spectator password failed\n", NET_AdrToString (net_from)); Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nrequires a spectator password\n\n", A2C_PRINT); return; } Info_RemoveKey (userinfo, "spectator"); Info_SetValueForStarKey (userinfo, "*spectator", "1", MAX_INFO_STRING); spectator = true; } else { s = Info_ValueForKey (userinfo, "password"); if (sv_password.string[0] && Q_stricmp(sv_password.string, "none") && strcmp(sv_password.string, s) ) { Com_Printf ("%s:password failed\n", NET_AdrToString (net_from)); Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c\nserver requires a password\n\n", A2C_PRINT); return; } spectator = false; Info_RemoveKey (userinfo, "password"); } #ifdef MAUTH // Check that the client is allowed to connect... if( net_from.type != NA_LOOPBACK && !COM_CheckParm("-nomauth") ) { authclient_t *authclient; // Try the auth token queue first... authclient = SV_AuthListFind(&authtokq, Info_ValueForKey(userinfo, "name")); if( authclient == NULL ) { // Fall back to checking if they had already connected and are in the // client queue already (i.e. were on here before a map change)... authclient = SV_AuthListFind(&authclientq, Info_ValueForKey(userinfo, "name")); if( authclient == NULL ) { // FIXME drop with reason Com_Printf ("MAUTH: Client %s not in a queue; connect refused.\n", Info_ValueForKey(userinfo, "name")); return; } } else { // They're valid, so move them to the main client queue from the // auth cache queue... SV_AuthListMove(&authtokq, &authclientq, authclient); } // Move to auth'd clients queue if they're valid... if( !authclient->valid ) { // FIXME drop with reason Com_Printf ("MAUTH: Client %s not validated yet; connect refused.\n", Info_ValueForKey(userinfo, "name")); return; } //SV_AuthListPrint(&authtokq); //SV_AuthListPrint(&authclientq); Com_Printf ("MAUTH: Client %s connection allowed.\n", Info_ValueForKey(userinfo, "name")); } else { Com_Printf("MAUTH: loopback or disabled; allowing client connection.\n"); } #endif adr = net_from; // if there is already a slot for this ip, reuse it for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) { if (cl->state == cs_free) continue; if (NET_CompareBaseAdr (adr, cl->netchan.remote_address) && ( cl->netchan.qport == qport || adr.port == cl->netchan.remote_address.port )) { if (cl->state == cs_connected) { Com_Printf ("%s:dup connect\n", NET_AdrToString (adr)); return; } Com_Printf ("%s:reconnect\n", NET_AdrToString (adr)); if (cl->state == cs_spawned) { SV_DropClient (cl); SV_ClearReliable (cl); // don't send the disconnect } cl->state = cs_free; break; } } // count up the clients and spectators and find an empty client slot clients = spectators = 0; newcl = NULL; for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++,cl++) { if (cl->state == cs_free) { if (!newcl) newcl = cl; // grab first available slot continue; } if (cl->spectator) spectators++; else clients++; } // if at server limits, refuse connection if ( (spectator && spectators >= (int)maxspectators.value) || (!spectator && clients >= (int)maxclients.value) || !newcl) { Com_Printf ("%s:full connect\n", NET_AdrToString (adr)); Netchan_OutOfBandPrint (NS_SERVER, adr, "%c\nserver is full\n\n", A2C_PRINT); return; } // build a new connection // accept the new client // this is the only place a client_t is ever initialized memset (newcl, 0, sizeof(*newcl)); newcl->userid = SV_GenerateUserID(); strlcpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)); Netchan_OutOfBandPrint (NS_SERVER, adr, "%c", S2C_CONNECTION ); Netchan_Setup (NS_SERVER, &newcl->netchan, adr, qport); newcl->state = cs_connected; SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf)); newcl->datagram.allowoverflow = true; // spectator mode can ONLY be set at join time newcl->spectator = spectator; // extract extensions bits newcl->extensions = atoi(Info_ValueForKey(newcl->userinfo, "*z_ext")); Info_RemoveKey (newcl->userinfo, "*z_ext"); #ifdef VWEP_TEST newcl->extensions |= atoi(Info_ValueForKey(newcl->userinfo, "*vwtest")) ? Z_EXT_VWEP : 0; Info_RemoveKey (newcl->userinfo, "*vwtest"); #endif // See if the client is using a proxy. The best test I can come up with for now... newcl->uses_proxy = *Info_ValueForKey(newcl->userinfo, "Qizmo") ? true : false; edictnum = (newcl - svs.clients) + 1; ent = EDICT_NUM(edictnum); ent->inuse = true; newcl->edict = ent; // parse some info from the info strings SV_ExtractFromUserinfo (newcl); // JACK: Init the floodprot stuff. for (i=0; i<10; i++) newcl->whensaid[i] = 0.0; newcl->whensaidhead = 0; newcl->lockedtill = 0; // call the progs to get default spawn parms for the new client PR_ExecuteProgram (pr_global_struct->SetNewParms); for (i=0 ; i<NUM_SPAWN_PARMS ; i++) newcl->spawn_parms[i] = (&pr_global_struct->parm1)[i]; if (newcl->spectator) Com_Printf ("Spectator %s connected\n", newcl->name); else Com_DPrintf ("Client %s connected\n", newcl->name); newcl->sendinfo = true; }
/* ================== SVC_DirectConnect A connection request that did not come from the master ================== */ static void SVC_DirectConnect (void) { char userinfo[1024]; static int userid; netadr_t adr; int i; client_t *cl, *newcl; client_t temp; edict_t *ent; int edictnum; const char *s; int clients, spectators; qboolean spectator; q_strlcpy (userinfo, Cmd_Argv(2), sizeof(userinfo)); // check for password or spectator_password s = Info_ValueForKey (userinfo, "spectator"); if (s[0] && strcmp(s, "0")) { if (spectator_password.string[0] && q_strcasecmp(spectator_password.string, "none") && strcmp(spectator_password.string, s) ) { // failed Con_Printf ("%s:spectator password failed\n", NET_AdrToString (net_from)); Netchan_OutOfBandPrint (net_from, "%c\nrequires a spectator password\n\n", A2C_PRINT); return; } Info_SetValueForStarKey (userinfo, "*spectator", "1", MAX_INFO_STRING); spectator = true; Info_RemoveKey (userinfo, "spectator"); // remove passwd } else { s = Info_ValueForKey (userinfo, "password"); if (password.string[0] && q_strcasecmp(password.string, "none") && strcmp(password.string, s) ) { Con_Printf ("%s:password failed\n", NET_AdrToString (net_from)); Netchan_OutOfBandPrint (net_from, "%c\nserver requires a password\n\n", A2C_PRINT); return; } spectator = false; Info_RemoveKey (userinfo, "password"); // remove passwd } adr = net_from; userid++; // so every client gets a unique id newcl = &temp; memset (newcl, 0, sizeof(client_t)); newcl->userid = userid; newcl->portals = atoi(Cmd_Argv(1)); // works properly if (!sv_highchars.integer) { byte *p, *q; for (p = (byte *)newcl->userinfo, q = (byte *)userinfo; *q && p < (byte *)newcl->userinfo + sizeof(newcl->userinfo)-1; q++) { if (*q > 31 && *q <= 127) *p++ = *q; } } else { q_strlcpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)); } // if there is already a slot for this ip, drop it for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) { if (cl->state == cs_free) continue; if (NET_CompareAdr (adr, cl->netchan.remote_address)) { Con_Printf ("%s:reconnect\n", NET_AdrToString (adr)); SV_DropClient (cl); break; } } // count up the clients and spectators clients = 0; spectators = 0; for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) { if (cl->state == cs_free) continue; if (cl->spectator) spectators++; else clients++; } // if at server limits, refuse connection if (maxclients.integer > MAX_CLIENTS) Cvar_SetValue ("maxclients", MAX_CLIENTS); if (maxspectators.integer > MAX_CLIENTS) Cvar_SetValue ("maxspectators", MAX_CLIENTS); if (maxspectators.integer + maxclients.integer > MAX_CLIENTS) Cvar_SetValue ("maxspectators", MAX_CLIENTS - maxspectators.integer + maxclients.integer); if ( (spectator && spectators >= maxspectators.integer) || (!spectator && clients >= maxclients.integer) ) { Con_Printf ("%s:full connect\n", NET_AdrToString (adr)); Netchan_OutOfBandPrint (adr, "%c\nserver is full\n\n", A2C_PRINT); return; } // find a client slot newcl = NULL; for (i = 0, cl = svs.clients; i < MAX_CLIENTS; i++, cl++) { if (cl->state == cs_free) { newcl = cl; break; } } if (!newcl) { Con_Printf ("WARNING: miscounted available clients\n"); return; } // build a new connection // accept the new client // this is the only place a client_t is ever initialized *newcl = temp; Netchan_OutOfBandPrint (adr, "%c", S2C_CONNECTION ); edictnum = (newcl-svs.clients)+1; Netchan_Setup (&newcl->netchan, adr); newcl->state = cs_connected; SZ_Init (&newcl->datagram, newcl->datagram_buf, sizeof(newcl->datagram_buf)); newcl->datagram.allowoverflow = true; // spectator mode can ONLY be set at join time newcl->spectator = spectator; ent = EDICT_NUM(edictnum); newcl->edict = ent; ED_ClearEdict (ent); // parse some info from the info strings SV_ExtractFromUserinfo (newcl); // JACK: Init the floodprot stuff. for (i = 0; i < 10; i++) newcl->whensaid[i] = 0.0; newcl->whensaidhead = 0; newcl->lockedtill = 0; // call the progs to get default spawn parms for the new client PR_ExecuteProgram (pr_global_struct->SetNewParms); for (i = 0; i < NUM_SPAWN_PARMS; i++) newcl->spawn_parms[i] = (&pr_global_struct->parm1)[i]; if (newcl->spectator) Con_Printf ("Spectator %s connected\n", newcl->name); else Con_DPrintf ("Client %s connected\n", newcl->name); }