diff options
-rw-r--r-- | src/sv_main.c | 605 |
1 files changed, 319 insertions, 286 deletions
diff --git a/src/sv_main.c b/src/sv_main.c index d74ac63..5d44710 100644 --- a/src/sv_main.c +++ b/src/sv_main.c @@ -549,25 +549,6 @@ static void SVC_GetChallenge(void) "challenge %u p=34,35,36", challenge); } -static void send_redirect_hack(const char *addr) -{ - Netchan_OutOfBand(NS_SERVER, &net_from, "client_connect"); - - MSG_WriteLong(1); - MSG_WriteLong(0); - MSG_WriteByte(svc_print); - MSG_WriteByte(PRINT_HIGH); - MSG_WriteString(va("Server is full. Redirecting you to %s...\n", addr)); - MSG_WriteByte(svc_stufftext); - MSG_WriteString(va("connect %s\n", addr)); - - NET_SendPacket(NS_SERVER, &net_from, msg_write.cursize, msg_write.data); - SZ_Clear(&msg_write); -} - -#define SV_OobPrintf(...) \ - Netchan_OutOfBand( NS_SERVER, &net_from, "print\n" __VA_ARGS__ ) - /* ================== SVC_DirectConnect @@ -575,234 +556,230 @@ SVC_DirectConnect A connection request that did not come from the master ================== */ -static void SVC_DirectConnect(void) -{ - char userinfo[MAX_INFO_STRING]; - char reconnect_var[16]; - char reconnect_val[16]; - int i, number, count; - client_t *cl, *newcl, *lastcl; - int protocol, version; + +typedef struct { + int protocol; // major version + int version; // minor version int qport; int challenge; - qboolean allow; - char *info, *s; + int maxlength; - netchan_type_t nctype; - char *ncstring, *acstring; - char dlstring[MAX_INFO_STRING]; - int reserved; + int nctype; qboolean has_zlib; - protocol = atoi(Cmd_Argv(1)); - qport = atoi(Cmd_Argv(2)) ; - challenge = atoi(Cmd_Argv(3)); + int reserved; // hidden client slots + char reconnect_var[16]; + char reconnect_val[16]; +} conn_params_t; - Com_DPrintf("%s: protocol=%i, qport=%i, challenge=%i\n", - __func__, protocol, qport, challenge); +#define reject(...) \ + (Netchan_OutOfBand(NS_SERVER, &net_from, "print\n" __VA_ARGS__), qfalse) - if (protocol < PROTOCOL_VERSION_DEFAULT || - protocol > PROTOCOL_VERSION_Q2PRO) { - SV_OobPrintf("Unsupported protocol version %d.\n", protocol); - Com_DPrintf(" rejected connect with protocol %i\n", protocol); - return; - } +static qboolean parse_basic_params(conn_params_t *p) +{ + p->protocol = atoi(Cmd_Argv(1)); + p->qport = atoi(Cmd_Argv(2)) ; + p->challenge = atoi(Cmd_Argv(3)); - if (!NET_IsLocalAddress(&net_from)) { - addrmatch_t *match; + // check for invalid protocol version + if (p->protocol < PROTOCOL_VERSION_OLD || + p->protocol > PROTOCOL_VERSION_Q2PRO) + return reject("Unsupported protocol version %d.\n", p->protocol); - // see if the challenge is valid - for (i = 0; i < MAX_CHALLENGES; i++) { - if (!svs.challenges[i].challenge) { - continue; - } - if (NET_IsEqualBaseAdr(&net_from, &svs.challenges[i].adr)) { - if (svs.challenges[i].challenge == challenge) - break; // good - SV_OobPrintf("Bad challenge.\n"); - Com_DPrintf(" rejected - bad challenge.\n"); - return; - } - } - if (i == MAX_CHALLENGES) { - SV_OobPrintf("No challenge for address.\n"); - Com_DPrintf(" rejected - no challenge.\n"); - return; - } - svs.challenges[i].challenge = 0; + // check for valid, but outdated protocol version + if (p->protocol < PROTOCOL_VERSION_DEFAULT) + return reject("You need Quake 2 version 3.19 or higher.\n"); - // check for banned address - if ((match = SV_MatchAddress(&sv_banlist, &net_from)) != NULL) { - s = match->comment; - if (!*s) { - s = "Your IP address is banned from this server."; - } - SV_OobPrintf("%s\nConnection refused.\n", s); - Com_DPrintf(" rejected connect from banned IP\n"); - return; + return qtrue; +} + +static qboolean permit_connection(conn_params_t *p) +{ + addrmatch_t *match; + int i, count; + client_t *cl; + char *s; + + // loopback clients are permitted without any checks + if (NET_IsLocalAddress(&net_from)) + return qtrue; + + // see if the challenge is valid + for (i = 0; i < MAX_CHALLENGES; i++) { + if (!svs.challenges[i].challenge) + continue; + + if (NET_IsEqualBaseAdr(&net_from, &svs.challenges[i].adr)) { + if (svs.challenges[i].challenge == p->challenge) + break; // good + + return reject("Bad challenge.\n"); } + } - if (sv_locked->integer) { - SV_OobPrintf("Server is locked.\n"); - Com_DPrintf(" rejected - server is locked.\n"); - return; + if (i == MAX_CHALLENGES) + return reject("No challenge for address.\n"); + + svs.challenges[i].challenge = 0; + + // check for banned address + if ((match = SV_MatchAddress(&sv_banlist, &net_from)) != NULL) { + s = match->comment; + if (!*s) { + s = "Your IP address is banned from this server."; } + return reject("%s\nConnection refused.\n", s); + } + + // check for locked server + if (sv_locked->integer) + return reject("Server is locked.\n"); - // limit number of connections from single IP - if (sv_iplimit->integer > 0) { - count = 0; - FOR_EACH_CLIENT(cl) { - if (NET_IsEqualBaseAdr(&net_from, - &cl->netchan->remote_address)) { - if (cl->state == cs_zombie) { - count++; - } else { - count += 2; - } + // limit number of connections from single IP + if (sv_iplimit->integer > 0) { + count = 0; + FOR_EACH_CLIENT(cl) { + if (NET_IsEqualBaseAdr(&net_from, &cl->netchan->remote_address)) { + if (cl->state == cs_zombie) { + count++; + } else { + count += 2; } } - count >>= 1; - if (count >= sv_iplimit->integer) { - SV_OobPrintf("Too many connections from your IP address.\n"); - Com_DPrintf(" rejected - %d connections from this IP.\n", count); - return; - } } + count >>= 1; + if (count >= sv_iplimit->integer) + return reject("Too many connections from your IP address.\n"); } - // set maximum message length - maxlength = MAX_PACKETLEN_WRITABLE_DEFAULT; - has_zlib = qfalse; - if (protocol >= PROTOCOL_VERSION_R1Q2) { - has_zlib = qtrue; + return qtrue; +} + +static qboolean parse_packet_length(conn_params_t *p) +{ + char *s; + + // set maximum packet length + p->maxlength = MAX_PACKETLEN_WRITABLE_DEFAULT; + if (p->protocol >= PROTOCOL_VERSION_R1Q2) { s = Cmd_Argv(5); if (*s) { - maxlength = atoi(s); - if (maxlength < 0 || maxlength > MAX_PACKETLEN_WRITABLE) { - SV_OobPrintf("Invalid maximum message length.\n"); - Com_DPrintf(" rejected - bad maxmsglen.\n"); - return; - } - if (!maxlength) { - maxlength = MAX_PACKETLEN_WRITABLE; - } else if (maxlength < MIN_PACKETLEN) { - maxlength = MIN_PACKETLEN; - } + p->maxlength = atoi(s); + if (p->maxlength < 0 || p->maxlength > MAX_PACKETLEN_WRITABLE) + return reject("Invalid maximum message length.\n"); + + // 0 means highest available + if (!p->maxlength) + p->maxlength = MAX_PACKETLEN_WRITABLE; } } - if (!NET_IsLocalAddress(&net_from)) { - // cap maximum message length for real connections - if (net_maxmsglen->integer > 0 && maxlength > net_maxmsglen->integer) { - maxlength = net_maxmsglen->integer; - } + if (!NET_IsLocalAddress(&net_from) && net_maxmsglen->integer > 0) { + // cap to server defined maximum value + if (p->maxlength > net_maxmsglen->integer) + p->maxlength = net_maxmsglen->integer; } - if (protocol == PROTOCOL_VERSION_R1Q2) { + // don't allow too small packets + if (p->maxlength < MIN_PACKETLEN) + p->maxlength = MIN_PACKETLEN; + + return qtrue; +} + +static qboolean parse_enhanced_params(conn_params_t *p) +{ + char *s; + + if (p->protocol == PROTOCOL_VERSION_R1Q2) { // set minor protocol version s = Cmd_Argv(6); if (*s) { - version = atoi(s); - clamp(version, PROTOCOL_VERSION_R1Q2_MINIMUM, + p->version = atoi(s); + clamp(p->version, + PROTOCOL_VERSION_R1Q2_MINIMUM, PROTOCOL_VERSION_R1Q2_CURRENT); } else { - version = PROTOCOL_VERSION_R1Q2_MINIMUM; + p->version = PROTOCOL_VERSION_R1Q2_MINIMUM; } - nctype = NETCHAN_OLD; - ncstring = ""; - } else if (protocol == PROTOCOL_VERSION_Q2PRO) { + p->nctype = NETCHAN_OLD; + p->has_zlib = qtrue; + } else if (p->protocol == PROTOCOL_VERSION_Q2PRO) { // set netchan type s = Cmd_Argv(6); if (*s) { - nctype = atoi(s); - if (nctype == NETCHAN_OLD) { - ncstring = " nc=0"; - } else if (nctype == NETCHAN_NEW) { - ncstring = " nc=1"; - } else { - SV_OobPrintf("Invalid netchan type.\n"); - Com_DPrintf(" rejected - bad nctype.\n"); - return; - } + p->nctype = atoi(s); + if (p->nctype < NETCHAN_OLD || p->nctype > NETCHAN_NEW) + return reject("Invalid netchan type.\n"); } else { - nctype = NETCHAN_NEW; - ncstring = " nc=1"; + p->nctype = NETCHAN_NEW; } // set zlib s = Cmd_Argv(7); - if (*s && !atoi(s)) { - has_zlib = qfalse; + if (*s) { + p->has_zlib = !!atoi(s); + } else { + p->has_zlib = qtrue; } // set minor protocol version s = Cmd_Argv(8); if (*s) { - version = atoi(s); - clamp(version, PROTOCOL_VERSION_Q2PRO_MINIMUM, + p->version = atoi(s); + clamp(p->version, + PROTOCOL_VERSION_Q2PRO_MINIMUM, PROTOCOL_VERSION_Q2PRO_CURRENT); - if (version == PROTOCOL_VERSION_Q2PRO_RESERVED) { - version--; // never use this version + if (p->version == PROTOCOL_VERSION_Q2PRO_RESERVED) { + p->version--; // never use this version } } else { - version = PROTOCOL_VERSION_Q2PRO_MINIMUM; + p->version = PROTOCOL_VERSION_Q2PRO_MINIMUM; } - } else { - nctype = NETCHAN_OLD; - ncstring = ""; - version = 0; } + return qtrue; +} + +static qboolean parse_userinfo(conn_params_t *params, char *userinfo) +{ + char *info, *s; + // validate userinfo info = Cmd_Argv(4); - if (!info[0]) { - SV_OobPrintf("Empty userinfo string.\n"); - Com_DPrintf(" rejected - empty userinfo.\n"); - return; - } + if (!info[0]) + return reject("Empty userinfo string.\n"); - if (!Info_Validate(info)) { - SV_OobPrintf("Malformed userinfo string.\n"); - Com_DPrintf(" rejected - malformed userinfo.\n"); - return; - } + if (!Info_Validate(info)) + return reject("Malformed userinfo string.\n"); s = Info_ValueForKey(info, "name"); - if (COM_IsWhite(s)) { - SV_OobPrintf("Please set your name before connecting.\n"); - Com_DPrintf(" rejected - empty name.\n"); - return; - } + if (COM_IsWhite(s)) + return reject("Please set your name before connecting.\n"); // check password s = Info_ValueForKey(info, "password"); - reserved = 0; if (sv_password->string[0]) { - if (!s[0]) { - SV_OobPrintf("Please set your password before connecting.\n"); - Com_DPrintf(" rejected - empty password.\n"); - return; - } - if (SV_RateLimited(&svs.ratelimit_auth)) { - SV_OobPrintf("Invalid password.\n"); - Com_DPrintf(" rejected - auth attempt limit exceeded.\n"); - return; - } + if (!s[0]) + return reject("Please set your password before connecting.\n"); + + if (SV_RateLimited(&svs.ratelimit_auth)) + return reject("Invalid password.\n"); + if (strcmp(sv_password->string, s)) { svs.ratelimit_auth.count++; - SV_OobPrintf("Invalid password.\n"); - Com_DPrintf(" rejected - invalid password.\n"); - return; + return reject("Invalid password.\n"); } // allow them to use reserved slots } else if (!sv_reserved_password->string[0] || strcmp(sv_reserved_password->string, s)) { - // in no reserved password is set on the server, do not allow + // if no reserved password is set on the server, do not allow // anyone to access reserved slots at all - reserved = sv_reserved_slots->integer; + params->reserved = sv_reserved_slots->integer; } - Q_strlcpy(userinfo, info, sizeof(userinfo)); + // copy userinfo off + Q_strlcpy(userinfo, info, MAX_INFO_STRING); // make sure mvdspec key is not set Info_RemoveKey(userinfo, "mvdspec"); @@ -814,130 +791,203 @@ static void SVC_DirectConnect(void) // force the IP key/value pair so the game can filter based on ip s = NET_AdrToString(&net_from); - if (!Info_SetValueForKey(userinfo, "ip", s)) { - SV_OobPrintf("Oversize userinfo string.\n"); - Com_DPrintf(" rejected - oversize userinfo.\n"); - return; - } + if (!Info_SetValueForKey(userinfo, "ip", s)) + return reject("Oversize userinfo string.\n"); + + return qtrue; +} + +static void redirect(const char *addr) +{ + Netchan_OutOfBand(NS_SERVER, &net_from, "client_connect"); + + // set up a fake server netchan + MSG_WriteLong(1); + MSG_WriteLong(0); + MSG_WriteByte(svc_print); + MSG_WriteByte(PRINT_HIGH); + MSG_WriteString(va("Server is full. Redirecting you to %s...\n", addr)); + MSG_WriteByte(svc_stufftext); + MSG_WriteString(va("connect %s\n", addr)); + + NET_SendPacket(NS_SERVER, &net_from, msg_write.cursize, msg_write.data); + SZ_Clear(&msg_write); +} - newcl = NULL; - reconnect_var[0] = 0; - reconnect_val[0] = 0; +static client_t *find_client_slot(conn_params_t *params) +{ + client_t *cl; + char *s; + int i; // if there is already a slot for this ip, reuse it FOR_EACH_CLIENT(cl) { if (NET_IsEqualAdr(&net_from, &cl->netchan->remote_address)) { if (cl->state == cs_zombie) { - strcpy(reconnect_var, cl->reconnect_var); - strcpy(reconnect_val, cl->reconnect_val); + strcpy(params->reconnect_var, cl->reconnect_var); + strcpy(params->reconnect_val, cl->reconnect_val); } else { SV_DropClient(cl, "reconnected"); } Com_DPrintf("%s: reconnect\n", NET_AdrToString(&net_from)); SV_RemoveClient(cl); - newcl = cl; - break; + return cl; } } - // find a client slot - if (!newcl) { - // check for forced redirect to a different address - if (sv_redirect_address->string[0] == '!' && - (!sv_reserved_slots->integer || reserved)) { - send_redirect_hack(sv_redirect_address->string + 1); - Com_DPrintf(" rejected - forced redirect.\n"); - return; - } - lastcl = svs.client_pool + sv_maxclients->integer - reserved; - for (newcl = svs.client_pool; newcl < lastcl; newcl++) { - if (!newcl->state) { - break; - } - } - if (newcl == lastcl) { - if (sv_reserved_slots->integer && !reserved) { - SV_OobPrintf("Server and reserved slots are full.\n"); - Com_DPrintf(" rejected - reserved slots are full.\n"); - } else { - // optionally redirect them to a different address - if (sv_redirect_address->string[0]) { - send_redirect_hack(sv_redirect_address->string); - } else { - SV_OobPrintf("Server is full.\n"); - } - Com_DPrintf(" rejected - server is full.\n"); - } - return; - } + // check for forced redirect to a different address + s = sv_redirect_address->string; + if (*s == '!' && sv_reserved_slots->integer == params->reserved) + return redirect(s + 1), NULL; + + // find a free client slot + for (i = 0; i < sv_maxclients->integer - params->reserved; i++) { + cl = &svs.client_pool[i]; + if (cl->state == cs_free) + return cl; } - // build a new connection - // accept the new client - // this is the only place a client_t is ever initialized - memset(newcl, 0, sizeof(*newcl)); - number = newcl - svs.client_pool; - newcl->number = newcl->slot = number; - newcl->challenge = challenge; // save challenge for checksumming - newcl->protocol = protocol; - newcl->version = version; - newcl->has_zlib = has_zlib; - newcl->edict = EDICT_NUM(number + 1); - newcl->gamedir = fs_game->string; - newcl->mapname = sv.name; - newcl->configstrings = (char *)sv.configstrings; - newcl->pool = (edict_pool_t *)&ge->edicts; - newcl->cm = &sv.cm; - newcl->spawncount = sv.spawncount; - newcl->maxclients = sv_maxclients->integer; - strcpy(newcl->reconnect_var, reconnect_var); - strcpy(newcl->reconnect_val, reconnect_val); -#if USE_FPS - newcl->framediv = sv.framediv; - newcl->settings[CLS_FPS] = BASE_FRAMERATE; -#endif + // clients that know the password are never redirected + if (sv_reserved_slots->integer != params->reserved) + return reject("Server and reserved slots are full.\n"), NULL; + + // optionally redirect them to a different address + if (*s) + return redirect(s), NULL; + + return reject("Server is full.\n"), NULL; +} + +static void init_pmove_and_es_flags(client_t *newcl) +{ + int force; // copy default pmove parameters newcl->pmp = sv_pmp; newcl->pmp.airaccelerate = sv_airaccelerate->integer ? qtrue : qfalse; - // r1q2 extensions - i = 2; - if (protocol == PROTOCOL_VERSION_R1Q2 || - protocol == PROTOCOL_VERSION_Q2PRO) { + // common extensions + force = 2; + if (newcl->protocol >= PROTOCOL_VERSION_R1Q2) { newcl->pmp.speedmult = 2; - i = 1; + force = 1; } - newcl->pmp.strafehack = sv_strafejump_hack->integer >= i ? qtrue : qfalse; + newcl->pmp.strafehack = sv_strafejump_hack->integer >= force ? qtrue : qfalse; - if (protocol == PROTOCOL_VERSION_R1Q2) { + // r1q2 extensions + if (newcl->protocol == PROTOCOL_VERSION_R1Q2) { newcl->esFlags |= MSG_ES_BEAMORIGIN; - if (version >= PROTOCOL_VERSION_R1Q2_LONG_SOLID) { + if (newcl->version >= PROTOCOL_VERSION_R1Q2_LONG_SOLID) { newcl->esFlags |= MSG_ES_LONGSOLID; } } // q2pro extensions - i = 2; - if (protocol == PROTOCOL_VERSION_Q2PRO) { + force = 2; + if (newcl->protocol == PROTOCOL_VERSION_Q2PRO) { if (sv_qwmod->integer) { PmoveEnableQW(&newcl->pmp); } newcl->pmp.flyhack = qtrue; newcl->pmp.flyfriction = 4; newcl->esFlags |= MSG_ES_UMASK; - if (version >= PROTOCOL_VERSION_Q2PRO_LONG_SOLID) { + if (newcl->version >= PROTOCOL_VERSION_Q2PRO_LONG_SOLID) { newcl->esFlags |= MSG_ES_LONGSOLID; } - if (version >= PROTOCOL_VERSION_Q2PRO_BEAM_ORIGIN) { + if (newcl->version >= PROTOCOL_VERSION_Q2PRO_BEAM_ORIGIN) { newcl->esFlags |= MSG_ES_BEAMORIGIN; } - if (version >= PROTOCOL_VERSION_Q2PRO_WATERJUMP_HACK) { - i = 1; + if (newcl->version >= PROTOCOL_VERSION_Q2PRO_WATERJUMP_HACK) { + force = 1; } } - newcl->pmp.waterhack = sv_waterjump_hack->integer >= i ? qtrue : qfalse; + newcl->pmp.waterhack = sv_waterjump_hack->integer >= force ? qtrue : qfalse; +} + +static void send_connect_packet(client_t *newcl, int nctype) +{ + const char *ncstring = ""; + const char *acstring = ""; + const char *dlstring1 = ""; + const char *dlstring2 = ""; + + if (newcl->protocol == PROTOCOL_VERSION_Q2PRO) { + if (nctype == NETCHAN_NEW) + ncstring = " nc=1"; + else + ncstring = " nc=0"; + } + +#if USE_AC_SERVER + if (!sv_force_reconnect->string[0] || newcl->reconnect_var[0]) + acstring = AC_ClientConnect(newcl); +#endif + + if (sv_downloadserver->string[0]) { + dlstring1 = " dlserver="; + dlstring2 = sv_downloadserver->string; + } + + Netchan_OutOfBand(NS_SERVER, &net_from, "client_connect%s%s%s%s map=%s", + ncstring, acstring, dlstring1, dlstring2, newcl->mapname); +} + +static void SVC_DirectConnect(void) +{ + char userinfo[MAX_INFO_STRING]; + conn_params_t params; + client_t *newcl; + int number; + qboolean allow; + char *reason; + + memset(¶ms, 0, sizeof(params)); + + // parse and validate parameters + if (!parse_basic_params(¶ms)) + return; + if (!permit_connection(¶ms)) + return; + if (!parse_packet_length(¶ms)) + return; + if (!parse_enhanced_params(¶ms)) + return; + if (!parse_userinfo(¶ms, userinfo)) + return; + + // find a free client slot + newcl = find_client_slot(¶ms); + if (!newcl) + return; + + number = newcl - svs.client_pool; + + // 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->number = newcl->slot = number; + newcl->challenge = params.challenge; // save challenge for checksumming + newcl->protocol = params.protocol; + newcl->version = params.version; + newcl->has_zlib = params.has_zlib; + newcl->edict = EDICT_NUM(number + 1); + newcl->gamedir = fs_game->string; + newcl->mapname = sv.name; + newcl->configstrings = (char *)sv.configstrings; + newcl->pool = (edict_pool_t *)&ge->edicts; + newcl->cm = &sv.cm; + newcl->spawncount = sv.spawncount; + newcl->maxclients = sv_maxclients->integer; + strcpy(newcl->reconnect_var, params.reconnect_var); + strcpy(newcl->reconnect_val, params.reconnect_val); +#if USE_FPS + newcl->framediv = sv.framediv; + newcl->settings[CLS_FPS] = BASE_FRAMERATE; +#endif + + init_pmove_and_es_flags(newcl); // get the game a chance to reject this connection or modify the userinfo sv_client = newcl; @@ -946,50 +996,32 @@ static void SVC_DirectConnect(void) sv_client = NULL; sv_player = NULL; if (!allow) { - char *reason; - reason = Info_ValueForKey(userinfo, "rejmsg"); if (*reason) { - SV_OobPrintf("%s\nConnection refused.\n", reason); + reject("%s\nConnection refused.\n", reason); } else { - SV_OobPrintf("Connection refused.\n"); + reject("Connection refused.\n"); } - Com_DPrintf(" game rejected a connection.\n"); return; } // setup netchan - newcl->netchan = Netchan_Setup(NS_SERVER, nctype, &net_from, - qport, maxlength, protocol); + newcl->netchan = Netchan_Setup(NS_SERVER, params.nctype, + &net_from, params.qport, + params.maxlength, + params.protocol); newcl->numpackets = 1; // parse some info from the info strings Q_strlcpy(newcl->userinfo, userinfo, sizeof(newcl->userinfo)); SV_UserinfoChanged(newcl); -#if USE_AC_SERVER - if (!sv_force_reconnect->string[0] || reconnect_var[0]) { - acstring = AC_ClientConnect(newcl); - } else -#endif - { - acstring = ""; - } - - if (sv_downloadserver->string[0]) { - Q_snprintf(dlstring, sizeof(dlstring), " dlserver=%s", - sv_downloadserver->string); - } else { - dlstring[0] = 0; - } - // send the connect packet to the client - Netchan_OutOfBand(NS_SERVER, &net_from, "client_connect%s%s%s map=%s", - ncstring, acstring, dlstring, newcl->mapname); + send_connect_packet(newcl, params.nctype); SV_InitClientSend(newcl); - if (protocol == PROTOCOL_VERSION_DEFAULT) { + if (newcl->protocol == PROTOCOL_VERSION_DEFAULT) { newcl->WriteFrame = SV_WriteFrameToClient_Default; } else { newcl->WriteFrame = SV_WriteFrameToClient_Enhanced; @@ -1046,7 +1078,8 @@ static void SVC_RemoteCommand(void) if (i == 0) { Com_Printf("Invalid rcon from %s:\n%s\n", NET_AdrToString(&net_from), string); - SV_OobPrintf("Bad rcon_password.\n"); + Netchan_OutOfBand(NS_SERVER, &net_from, + "print\nBad rcon_password.\n"); svs.ratelimit_rcon.count++; return; } |