/* ======================= CL_SendConnectPacket We have gotten a challenge from the server, so try and connect. ====================== */ void CL_SendConnectPacket (void) { netadr_t adr; int32_t port; if (!NET_StringToAdr (cls.servername, &adr)) { Com_Printf ("Bad server address\n"); cls.connect_time = 0; return; } if (adr.port == 0) adr.port = BigShort (PORT_SERVER); port = Cvar_VariableValue ("qport"); userinfo_modified = false; // if in compatibility mode, lie to server about this // client's protocol, but exclude localhost for this. if (cl_servertrick->value && strcmp(cls.servername, "localhost")) Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n", OLD_PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() ); else Netchan_OutOfBandPrint (NS_CLIENT, adr, "connect %i %i %i \"%s\"\n", PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo() ); }
/* <9a0ba> ../engine/sv_log.c:37 */ void Log_Printf(const char *fmt, ...) { va_list argptr; char string[1024]; time_t ltime; tm *today; LOGLIST_T *list; if (!g_psvs.log.net_log_ && !firstLog && !g_psvs.log.active) return; time(<ime); today = localtime(<ime); va_start(argptr, fmt); Q_snprintf(string,sizeof(string), "L %02i/%02i/%04i - %02i:%02i:%02i: ", today->tm_mon + 1, today->tm_mday, today->tm_year + 1900, today->tm_hour, today->tm_min, today->tm_sec); Q_vsnprintf(&string[Q_strlen(string)], sizeof(string) - Q_strlen(string), fmt, argptr); va_end(argptr); #ifdef REHLDS_FLIGHT_REC FR_Log("REHLDS_LOG", string); #endif if (g_psvs.log.net_log_ || firstLog != NULL) { if (g_psvs.log.net_log_) Netchan_OutOfBandPrint(NS_SERVER, g_psvs.log.net_address_, "log %s", string); for (list = firstLog; list != NULL; list = list->next) { if (sv_logsecret.value == 0.0f) Netchan_OutOfBandPrint(NS_SERVER, list->log.net_address_, "log %s", string); else Netchan_OutOfBandPrint(NS_SERVER, list->log.net_address_, "%c%s%s", S2A_LOGKEY, sv_logsecret.string, string); } } if (g_psvs.log.active && (g_psvs.maxclients > 1 || sv_log_singleplayer.value != 0.0f)) { if (mp_logecho.value != 0.0f) Con_Printf("%s", string); if (g_psvs.log.file) { if (mp_logfile.value != 0.0f) FS_FPrintf((FileHandle_t)g_psvs.log.file, "%s", string); } } }
/* * TV_Downstream_GetChallenge * * Returns a challenge number that can be used * in a subsequent client_connect command. * We do this to prevent denial of service attacks that * flood the server with invalid upstream IPs. With a * challenge, they must give a valid IP address. */ static void TV_Downstream_GetChallenge( const socket_t *socket, const netadr_t *address ) { int i; int oldest; int oldestTime; oldest = 0; oldestTime = 0x7fffffff; // see if we already have a challenge for this ip for( i = 0; i < MAX_CHALLENGES; i++ ) { if( NET_CompareBaseAddress( address, &tvs.challenges[i].adr ) ) break; if( tvs.challenges[i].time < oldestTime ) { oldestTime = tvs.challenges[i].time; oldest = i; } } if( i == MAX_CHALLENGES ) { // overwrite the oldest tvs.challenges[oldest].challenge = rand() & 0x7fff; tvs.challenges[oldest].adr = *address; tvs.challenges[oldest].time = tvs.realtime; i = oldest; } Netchan_OutOfBandPrint( socket, address, "challenge %i", tvs.challenges[i].challenge ); }
/** * @brief */ static void Cl_SendBroadcast(void) { const GList *e = cls.servers; while (e) { // update old ping times cl_server_info_t *s = (cl_server_info_t *) e->data; if (s->source == SERVER_SOURCE_BCAST) { s->ping_time = quetoo.ticks; s->ping = 999; } e = e->next; } net_addr_t addr; memset(&addr, 0, sizeof(addr)); addr.type = NA_BROADCAST; addr.port = htons(PORT_SERVER); Netchan_OutOfBandPrint(NS_UDP_CLIENT, &addr, "info %i", PROTOCOL_MAJOR); cls.broadcast_time = quetoo.ticks; }
/** * @brief */ void Cl_Ping_f(void) { net_addr_t addr; cl_server_info_t *server; if (Cmd_Argc() != 2) { Com_Print("Usage: %s <address>\n", Cmd_Argv(0)); return; } server = NULL; if (!Net_StringToNetaddr(Cmd_Argv(1), &addr)) { Com_Print("Invalid address\n"); return; } if (!addr.port) { // use default addr.port = (uint16_t) htons(PORT_SERVER); } server = Cl_ServerForNetaddr(&addr); if (!server) { // add it server = Cl_AddServer(&addr); server->source = SERVER_SOURCE_USER; } server->ping_time = quetoo.ticks; server->ping = 999; Com_Print("Pinging %s\n", Net_NetaddrToString(&server->addr)); Netchan_OutOfBandPrint(NS_UDP_CLIENT, &server->addr, "info %i", PROTOCOL_MAJOR); }
/* * We have gotten a challenge from the server, so try and * connect. */ void CL_SendConnectPacket(void) { netadr_t adr; int port; memset(&adr, 0, sizeof(adr)); if (!NET_StringToAdr(cls.servername, &adr)) { Com_Printf("Bad server address\n"); cls.connect_time = 0; return; } if (adr.port == 0) { adr.port = BigShort(PORT_SERVER); } port = Cvar_VariableValue("qport"); userinfo_modified = false; Netchan_OutOfBandPrint(NS_CLIENT, adr, "connect %i %i %i \"%s\"\n", PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo()); }
/* * TV_Downstream_MasterHeartbeat * Send a message to the master every few minutes to * let it know we are alive, and log information */ void TV_Downstream_MasterHeartbeat( void ) { int i; const socket_t *socket; tvs.lobby.last_heartbeat -= tvs.lobby.snapFrameTime; if( tvs.lobby.last_heartbeat > 0 ) return; tvs.lobby.last_heartbeat = HEARTBEAT_SECONDS * 1000; if( !tv_public->integer ) return; // send to group master for( i = 0; i < MAX_MASTERS; i++ ) { if( tv_master_adr[i].type != NA_NOTRANSMIT ) { Com_Printf( "Sending heartbeat to %s\n", NET_AddressToString( &tv_master_adr[i] ) ); socket = ( tv_master_adr[i].type == NA_IP6 ? &tvs.socket_udp6 : &tvs.socket_udp ); // warning: "DarkPlaces" is a protocol name here, not a game name. Do not replace it. Netchan_OutOfBandPrint( socket, &tv_master_adr[i], "heartbeat %s\n", "DarkPlaces" ); } } }
/* * Cl_Ping_f */ void Cl_Ping_f(void) { net_addr_t addr; cl_server_info_t *server; if (Cmd_Argc() != 2) { Com_Print("Usage: %s <address>\n", Cmd_Argv(0)); return; } server = NULL; if (!Net_StringToNetaddr(Cmd_Argv(1), &addr)) { Com_Print("Invalid address\n"); return; } if (!addr.port) // use default addr.port = (unsigned short) BigShort(PORT_SERVER); server = Cl_ServerForNetaddr(&addr); if (!server) { // add it server = Cl_AddServer(&addr); server->source = SERVER_SOURCE_USER; } server->ping_time = cls.real_time; server->ping = 0; Com_Print("Pinging %s\n", Net_NetaddrToString(server->addr)); Netchan_OutOfBandPrint(NS_CLIENT, server->addr, "info %i", PROTOCOL); }
/* ================= cGetChallenge Returns a challenge number that can be used in a subsequent client_connect command. We do this to prevent denial of service attacks that flood the server with invalid connection IPs. With a challenge, they must give a valid IP address. ================= */ static void cGetChallenge(int argc, char **argv) { int i; int oldest = 0; int oldestTime = 0x7FFFFFFF; // see if we already have a challenge for this ip for (i = 0; i < MAX_CHALLENGES; i++) { if (NET_CompareBaseAdr(&net_from, &svs.challenges[i].adr)) break; if (svs.challenges[i].time < oldestTime) { oldestTime = svs.challenges[i].time; oldest = i; } } if (i == MAX_CHALLENGES) { // overwrite the oldest svs.challenges[oldest].challenge = rand() & 0x7FFF; svs.challenges[oldest].adr = net_from; svs.challenges[oldest].time = appMilliseconds(); i = oldest; } // send it back Netchan_OutOfBandPrint(NS_SERVER, net_from, "challenge %d", svs.challenges[i].challenge); }
/* * Svc_Info * * Responds with short info for broadcast scans. */ static void Svc_Info(void) { char string[MAX_MSG_SIZE]; int i, count; int prot; if (sv_max_clients->integer == 1) return; // ignore in single player prot = atoi(Cmd_Argv(1)); if (prot != PROTOCOL) snprintf(string, sizeof(string), "%s: wrong protocol version\n", sv_hostname->string); else { count = 0; for (i = 0; i < sv_max_clients->integer; i++) { if (svs.clients[i].state >= SV_CLIENT_CONNECTED) count++; } snprintf(string, sizeof(string), "%-63s\\%-31s\\%-31s\\%d\\%d", sv_hostname->string, sv.name, Cvar_GetString("g_gameplay"), count, sv_max_clients->integer); } Netchan_OutOfBandPrint(NS_SERVER, net_from, "info\n%s", string); }
//================ // SV_MMHeartbeat // Send matchmaker a heartbeat with status //================ void SV_MMHeartbeat( void ) { static qboolean canhost = qfalse; netadr_t address; socket_t *socket; if( !sv_public->integer ) return; // never go public when not acting as a game server if( sv.state > ss_game ) return; if( !SV_MM_Initialized() || SV_MM_IsLocked() ) return; svc.last_mmheartbeat -= svc.snapFrameTime; if( svc.last_mmheartbeat > 0 && canhost == SV_MM_CanHost() ) return; if ( !SV_MM_NetAddress( &address ) ) return; svc.last_mmheartbeat = MM_HEARTBEAT_SECONDS * 1000; canhost = SV_MM_CanHost(); socket = ( address.type == NA_IP6 ? &svs.socket_udp6 : &svs.socket_udp ); Netchan_OutOfBandPrint( socket, &address, "heartbeat %s %d %d %s", canhost ? "yes":"no", APP_PROTOCOL_VERSION, SV_MM_GetSlotCount(), SV_MM_Salt() ); Com_Printf( "Sending heartbeat to matchmaker\n" ); }
/* * SVC_GetChallenge * * Returns a challenge number that can be used * in a subsequent client_connect command. * We do this to prevent denial of service attacks that * flood the server with invalid connection IPs. With a * challenge, they must give a valid IP address. */ static void SVC_GetChallenge( const socket_t *socket, const netadr_t *address ) { int i; int oldest; int oldestTime; oldest = 0; oldestTime = 0x7fffffff; if( sv_showChallenge->integer ) Com_Printf( "Challenge Packet %s\n", NET_AddressToString( address ) ); // see if we already have a challenge for this ip for( i = 0; i < MAX_CHALLENGES; i++ ) { if( NET_CompareBaseAddress( address, &svs.challenges[i].adr ) ) break; if( svs.challenges[i].time < oldestTime ) { oldestTime = svs.challenges[i].time; oldest = i; } } if( i == MAX_CHALLENGES ) { // overwrite the oldest svs.challenges[oldest].challenge = rand() & 0x7fff; svs.challenges[oldest].adr = *address; svs.challenges[oldest].time = Sys_Milliseconds(); i = oldest; } Netchan_OutOfBandPrint( socket, address, "challenge %i", svs.challenges[i].challenge ); }
/* ================ SVC_Info Responds with short info for broadcast scans The second parameter should be the current protocol version number. ================ */ void SVC_Info(void) { char string[64]; int i, count; int version; if (maxclients->value == 1) return; // ignore in single player version = atoi(Cmd_Argv(1)); if (version != PROTOCOL_VERSION) Com_sprintf(string, sizeof(string), "%s: wrong version\n", hostname->string, sizeof(string)); else { count = 0; for (i = 0; i < maxclients->value; i++) if (svs.clients[i].state >= cs_connected) count++; Com_sprintf(string, sizeof(string), "%16s %8s %2i/%2i\n", hostname->string, sv.name, count, (int)maxclients->value); } Netchan_OutOfBandPrint(NS_SERVER, net_from, "info\n%s", string); }
/* * @brief Returns a challenge number that can be used in a subsequent client_connect * command. * * We do this to prevent denial of service attacks that flood the server with * invalid connection IPs. With a challenge, they must give a valid address. */ static void Svc_GetChallenge(void) { uint16_t i, oldest; uint32_t oldest_time; oldest = 0; oldest_time = 0x7fffffff; // see if we already have a challenge for this ip for (i = 0; i < MAX_CHALLENGES; i++) { if (Net_CompareClientNetaddr(&net_from, &svs.challenges[i].addr)) break; if (svs.challenges[i].time < oldest_time) { oldest_time = svs.challenges[i].time; oldest = i; } } if (i == MAX_CHALLENGES) { // overwrite the oldest svs.challenges[oldest].challenge = Random() & 0x7fff; svs.challenges[oldest].addr = net_from; svs.challenges[oldest].time = quake2world.time; i = oldest; } // send it back Netchan_OutOfBandPrint(NS_UDP_SERVER, &net_from, "challenge %i", svs.challenges[i].challenge); }
void Master_Heartbeat (void) { char *string; int i; // pgm post3.19 change, cvar pointer not validated before dereferencing if (!dedicated || !dedicated->value) return; // only dedicated servers send heartbeats // pgm post3.19 change, cvar pointer not validated before dereferencing if (!public_server || !public_server->value) return; // a private dedicated game // check for time wraparound if (svs.last_heartbeat > svs.realtime) svs.last_heartbeat = svs.realtime; if (svs.realtime - svs.last_heartbeat < HEARTBEAT_SECONDS*1000) return; // not time to send yet svs.last_heartbeat = svs.realtime; // send the same string that we would give for a status OOB command string = SV_StatusString(); // send to group master for (i=0 ; i<MAX_MASTERS ; i++) if (master_adr[i].port) { Com_Printf ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i])); Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "heartbeat\n%s", string); } }
/* ================ cInfo Responds with short info for broadcast scans The second parameter should be the current protocol version number. ================ */ static void cInfo(int argc, char **argv) { if (sv_maxclients->integer == 1 || sv.state == ss_demo || sv.attractloop) return; // ignore in single player or demoplay int version = atoi(argv[1]); if (!version) { // we should reject this packet -- this is our "info" answer to local client (loopback packet) Com_DPrintf("rejected \"info\" answer\n"); return; } TString<64> Str; if (version != PROTOCOL_VERSION) Str.sprintf("%s: wrong version %d\n", hostname->string, version); else { int count = 0; for (int i = 0; i < sv_maxclients->integer; i++) if (svs.clients[i].state >= cs_connected) count++; Str.sprintf("%16s %8s %2d/%2d\n", hostname->string, sv.name, count, sv_maxclients->integer); } Netchan_OutOfBandPrint(NS_SERVER, net_from, "info\n%s", *Str); }
/* * ================= SVC_GetChallenge * * Returns a challenge number that can be used in a subsequent client_connect * command. We do this to prevent denial of service attacks that flood the * server with invalid connection IPs. With a challenge, they must give a * valid IP address. ================= */ void SVC_GetChallenge(void) { int i; int oldest; int oldestTime; oldest = 0; oldestTime = 0x7fffffff; /* see if we already have a challenge for this ip */ for (i = 0; i < MAX_CHALLENGES; i++) { if (NET_CompareBaseAdr(net_from, svs.challenges[i].adr)) break; if (svs.challenges[i].time < oldestTime) { oldestTime = svs.challenges[i].time; oldest = i; } } if (i == MAX_CHALLENGES) { /* overwrite the oldest */ svs.challenges[oldest].challenge = rand() & 0x7fff; svs.challenges[oldest].adr = net_from; svs.challenges[oldest].time = curtime; i = oldest; } /* send it back */ Netchan_OutOfBandPrint(NS_SERVER, net_from, "challenge %i", svs.challenges[i].challenge); }
/* ================= CL_CheckForResend Resend a connect message if the last one has timed out ================= */ void CL_CheckForResend( void ) { netadr_t adr; // if the local server is running and we aren't then connect if( cls.state == ca_disconnected && SV_Active( )) { cls.state = ca_connecting; Q_strncpy( cls.servername, "localhost", sizeof( cls.servername )); // we don't need a challenge on the localhost CL_SendConnectPacket(); return; } // resend if we haven't gotten a reply yet if( cls.demoplayback || cls.state != ca_connecting ) return; if(( host.realtime - cls.connect_time ) < 10.0f ) return; if( !NET_StringToAdr( cls.servername, &adr )) { MsgDev( D_ERROR, "CL_CheckForResend: bad server address\n" ); cls.state = ca_disconnected; return; } if( adr.port == 0 ) adr.port = BF_BigShort( PORT_SERVER ); cls.connect_time = host.realtime; // for retransmit requests MsgDev( D_NOTE, "Connecting to %s...\n", cls.servername ); Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" ); }
/* * ================= * Master_Shutdown * * Informs all masters that this server is going down * ================= */ void Master_Shutdown(void) { int i; // pgm post3.19 change, cvar pointer not validated before dereferencing if (!dedicated || !dedicated->value) { return; // only dedicated servers send heartbeats } // pgm post3.19 change, cvar pointer not validated before dereferencing if (!public_server || !public_server->value) { return; // a private dedicated game } // send to group master for (i = 0; i < MAX_MASTERS; i++) { if (master_adr[i].port) { if (i > 0) { Com_Printf("Sending heartbeat to %s\n", NET_AdrToString(master_adr[i])); } Netchan_OutOfBandPrint(NS_SERVER, master_adr[i], "shutdown"); } } }
static void Master_Heartbeat() { if (!DEDICATED) return; // only dedicated servers send heartbeats if (!public_server->integer) return; // a private dedicated game // check for time wraparound if (svs.last_heartbeat > svs.realtime) svs.last_heartbeat = svs.realtime; if (svs.realtime - svs.last_heartbeat < HEARTBEAT_SECONDS*1000) return; // not time to send yet svs.last_heartbeat = svs.realtime; // send the same string that we would give for a status OOB command const char *string = SV_StatusString(); // send to group master for (int i = 0; i < MAX_MASTERS; i++) if (master_adr[i].port) { appPrintf("Sending heartbeat to %s\n", NET_AdrToString(&master_adr[i])); Netchan_OutOfBandPrint(NS_SERVER, master_adr[i], "heartbeat\n%s", string); } }
/* * SV_MasterHeartbeat * Send a message to the master every few minutes to * let it know we are alive, and log information */ void SV_MasterHeartbeat( void ) { int i; svc.lastHeartbeat -= svc.snapFrameTime; if( svc.lastHeartbeat > 0 ) return; svc.lastHeartbeat = HEARTBEAT_SECONDS * 1000; if( !sv_public->integer ) return; // never go public when not acting as a game server if( sv.state > ss_game ) return; // send to group master for( i = 0; i < MAX_MASTERS; i++ ) { if( master_adr[i].type != NA_NOTRANSMIT ) { socket_t *socket; if( dedicated && dedicated->integer ) Com_Printf( "Sending heartbeat to %s\n", NET_AddressToString( &master_adr[i] ) ); socket = ( master_adr[i].type == NA_IP6 ? &svs.socket_udp6 : &svs.socket_udp ); // warning: "DarkPlaces" is a protocol name here, not a game name. Do not replace it. Netchan_OutOfBandPrint( socket, &master_adr[i], "heartbeat DarkPlaces\n" ); } } }
/* * SVC_SendInfoString */ static void SVC_SendInfoString( const socket_t *socket, const netadr_t *address, const char *requestType, const char *responseType, qboolean fullStatus ) { char *string; if( sv_showInfoQueries->integer ) Com_Printf( "%s Packet %s\n", requestType, NET_AddressToString( address ) ); // KoFFiE: When not public and coming from a LAN address // assume broadcast and respond anyway, otherwise ignore if( ( ( !sv_public->integer ) && ( !NET_IsLANAddress( address ) ) ) || ( sv_maxclients->integer == 1 ) ) { return; } // ignore when in invalid server state if( sv.state < ss_loading || sv.state > ss_game ) return; // don't reply when we are locked for mm // if( SV_MM_IsLocked() ) // return; // send the same string that we would give for a status OOB command string = SV_LongInfoString( fullStatus ); if( string ) Netchan_OutOfBandPrint( socket, address, "%s\n\\challenge\\%s%s", responseType, Cmd_Argv( 1 ), string ); }
/* ================= SVC_GetChallenge Returns a challenge number that can be used in a subsequent client_connect command. We do this to prevent denial of service attacks that flood the server with invalid connection IPs. With a challenge, they must give a valid IP address. ================= */ void SVC_GetChallenge (void) { int i; int oldest; int oldestTime; oldest = 0; oldestTime = 0x7fffffff; // see if we already have a challenge for this ip for (i = 0 ; i < MAX_CHALLENGES ; i++) { if (NET_CompareBaseAdr (net_from, svs.challenges[i].adr)) break; if (svs.challenges[i].time < oldestTime) { oldestTime = svs.challenges[i].time; oldest = i; } } if (i == MAX_CHALLENGES) { // overwrite the oldest svs.challenges[oldest].challenge = (rand() << 16) ^ rand(); svs.challenges[oldest].adr = net_from; svs.challenges[oldest].time = svs.realtime; i = oldest; } // send it back Netchan_OutOfBandPrint (NS_SERVER, net_from, "%c%i", S2C_CHALLENGE, svs.challenges[i].challenge); }
/* * @brief Sends heartbeat messages to master servers every 300s. */ void Sv_HeartbeatMasters(void) { const char *string; int32_t i; if (!dedicated->value) return; // only dedicated servers report to masters if (!sv_public->value) return; // a private dedicated game if (!svs.initialized) // we're not up yet return; if (svs.next_heartbeat > quetoo.time) return; // not time to send yet svs.next_heartbeat = quetoo.time + HEARTBEAT_SECONDS * 1000; // send the same string that we would give for a status command string = Sv_StatusString(); // send to each master server for (i = 0; i < MAX_MASTERS; i++) { if (svs.masters[i].port) { Com_Print("Sending heartbeat to %s\n", Net_NetaddrToString(&svs.masters[i])); Netchan_OutOfBandPrint(NS_UDP_SERVER, &svs.masters[i], "heartbeat\n%s", string); } } }
/* * CL_PingServer_f */ void CL_PingServer_f( void ) { char *address_string; char requestString[64]; netadr_t adr; serverlist_t *pingserver; socket_t *socket; if( Cmd_Argc() < 2 ) Com_Printf( "Usage: pingserver [ip:port]\n" ); address_string = Cmd_Argv( 1 ); if( !NET_StringToAddress( address_string, &adr ) ) return; pingserver = CL_ServerFindInList( masterList, address_string ); if( !pingserver ) pingserver = CL_ServerFindInList( favoritesList, address_string ); if( !pingserver ) return; // never request a second ping while awaiting for a ping reply if( pingserver->pingTimeStamp + SERVER_PINGING_TIMEOUT > Sys_Milliseconds() ) return; pingserver->pingTimeStamp = Sys_Milliseconds(); Q_snprintfz( requestString, sizeof( requestString ), "info %i %s %s", SERVERBROWSER_PROTOCOL_VERSION, filter_allow_full ? "full" : "", filter_allow_empty ? "empty" : "" ); socket = ( adr.type == NA_IP6 ? &cls.socket_udp6 : &cls.socket_udp ); Netchan_OutOfBandPrint( socket, &adr, requestString ); }
/* * CL_QueryGetInfoMessage */ static void CL_QueryGetInfoMessage( const char *cmdname ) { netadr_t adr; char *requeststring; char *server; //get what master server = Cmd_Argv( 1 ); if( !server || !( *server ) ) { Com_Printf( "%s: no address provided %s...\n", Cmd_Argv( 0 ), server ? server : "" ); return; } requeststring = va( cmdname ); // send a broadcast packet Com_DPrintf( "quering %s...\n", server ); if( NET_StringToAddress( server, &adr ) ) { socket_t *socket; if( NET_GetAddressPort( &adr ) == 0 ) NET_SetAddressPort( &adr, PORT_SERVER ); socket = ( adr.type == NA_IP6 ? &cls.socket_udp6 : &cls.socket_udp ); Netchan_OutOfBandPrint( socket, &adr, requeststring ); } else { Com_Printf( "Bad address: %s\n", server ); } }
/* * ================ * SVC_Info * * Responds with short info for broadcast scans * The second parameter should be the current protocol version number. * ================ */ void SVC_Info(void) { char string[64]; int i, count; int version; if (maxclients->value == 1) { return; // ignore in single player } version = atoi(Cmd_Argv(1)); if (version != PROTOCOL_VERSION) { // According to r1ch, this can be used to make servers endlessly ping each other // Com_sprintf (string, sizeof(string), "%s: wrong version\n", hostname->string, sizeof(string)); return; } else { count = 0; for (i = 0; i < maxclients->value; i++) { if (svs.clients[i].state >= cs_connected) { count++; } } Com_sprintf(string, sizeof(string), "%16s %8s %2i/%2i\n", hostname->string, sv.name, count, (int)maxclients->value); } Netchan_OutOfBandPrint(NS_SERVER, net_from, "info\n%s", string); }
/* * @brief */ void Cl_ParseServers(void) { cl_server_info_t *server; byte *buffptr = net_message.data + 12; byte *buffend = buffptr + net_message.size - 12; // parse the list while (buffptr + 1 < buffend) { net_addr_t addr; byte ip[4]; ip[0] = *buffptr++; // parse the address ip[1] = *buffptr++; ip[2] = *buffptr++; ip[3] = *buffptr++; uint16_t port = (*buffptr++) << 8; // and the port port += *buffptr++; char s[32]; g_snprintf(s, sizeof(s), "%d.%d.%d.%d:%d", ip[0], ip[1], ip[2], ip[3], port); Com_Debug("Parsed %s\n", s); if (!Net_StringToNetaddr(s, &addr)) { // make sure it's valid Com_Warn("Invalid address: %s\n", s); break; } if (!addr.port) // 0's mean we're done break; server = Cl_ServerForNetaddr(&addr); if (!server) server = Cl_AddServer(&addr); server->source = SERVER_SOURCE_INTERNET; } net_message.read = net_message.size; // then ping them GList *e = cls.servers; while (e) { server = (cl_server_info_t *) e->data; if (server->source == SERVER_SOURCE_INTERNET) { server->ping_time = cls.real_time; server->ping = 0; Netchan_OutOfBandPrint(NS_UDP_CLIENT, &server->addr, "info %i", PROTOCOL_MAJOR); } e = e->next; } }
static void M_ServerlistUpdateUDP (int nStart) { netadr_t adr; static qboolean didUpdateCheck = false; adr.port = htons(UDP_SERVERLIST_PORT); NET_StringToAdr(serverlist_udp_source1->string, &adr); //Netchan_OutOfBandPrint(NS_CLIENT, adr, "serverlist1 %d %s\n", nStart, g_szRandomServerlistString); Netchan_OutOfBandPrint(NS_CLIENT, adr, "serverlist2\n"); if (!didUpdateCheck && !g_notified_of_new_version) { // Not currently implemented on dplogin server, but it may work eventually: Netchan_OutOfBandPrint(NS_CLIENT, adr, "updatecheck1 " BUILD_S "\n"); // versioncheck / checkversion / buildcheck didUpdateCheck = true; } }
/* * Cl_ParseServersList */ void Cl_ParseServersList(void) { byte *buffptr; byte *buffend; byte ip[4]; unsigned short port; net_addr_t addr; cl_server_info_t *server; char s[32]; buffptr = net_message.data + 12; buffend = buffptr + net_message.size - 12; // parse the list while (buffptr + 1 < buffend) { ip[0] = *buffptr++; // parse the address ip[1] = *buffptr++; ip[2] = *buffptr++; ip[3] = *buffptr++; port = (*buffptr++) << 8; // and the port port += *buffptr++; snprintf(s, sizeof(s), "%d.%d.%d.%d:%d", ip[0], ip[1], ip[2], ip[3], port); if (!Net_StringToNetaddr(s, &addr)) { // make sure it's valid Com_Warn("Cl_ParseServersList: Invalid address: %s.\n", s); break; } if (!addr.port) // 0's mean we're done break; server = Cl_ServerForNetaddr(&addr); if (!server) server = Cl_AddServer(&addr); server->source = SERVER_SOURCE_INTERNET; } net_message.read = net_message.size; // then ping them server = cls.servers; while (server) { if (server->source == SERVER_SOURCE_INTERNET) { server->ping_time = cls.real_time; server->ping = 0; Netchan_OutOfBandPrint(NS_CLIENT, server->addr, "info %i", PROTOCOL); } server = server->next; } }