+ int n;
+ int pingtime;
+ serverlist_entry_t *entry = NULL;
+
+ // search the cache for this server and update it
+ for (n = 0;n < serverlist_cachecount;n++) {
+ entry = &serverlist_cache[ n ];
+ if (!strcmp(addressstring, entry->info.cname))
+ break;
+ }
+
+ if (n == serverlist_cachecount)
+ {
+ // LAN search doesnt require an answer from the master server so we wont
+ // know the ping nor will it be initialized already...
+
+ // find a slot
+ if (serverlist_cachecount == SERVERLIST_TOTALSIZE)
+ return -1;
+
+ if (serverlist_maxcachecount <= serverlist_cachecount)
+ {
+ serverlist_maxcachecount += 64;
+ serverlist_cache = (serverlist_entry_t *)Mem_Realloc(netconn_mempool, (void *)serverlist_cache, sizeof(serverlist_entry_t) * serverlist_maxcachecount);
+ }
+ entry = &serverlist_cache[n];
+
+ memset(entry, 0, sizeof(*entry));
+ // store the data the engine cares about (address and ping)
+ strlcpy(entry->info.cname, addressstring, sizeof(entry->info.cname));
+ entry->info.ping = 100000;
+ entry->querytime = host.realtime;
+ // if not in the slist menu we should print the server to console
+ if (serverlist_consoleoutput)
+ Con_Printf("querying %s\n", addressstring);
+ ++serverlist_cachecount;
+ }
+ // if this is the first reply from this server, count it as having replied
+ pingtime = (int)((host.realtime - entry->querytime) * 1000.0 + 0.5);
+ pingtime = bound(0, pingtime, 9999);
+ if (entry->query == SQS_REFRESHING) {
+ entry->info.ping = pingtime;
+ entry->query = SQS_QUERIED;
+ } else {
+ // convert to unsigned to catch the -1
+ // I still dont like this but its better than the old 10000 magic ping number - as in easier to type and read :( [11/8/2007 Black]
+ entry->info.ping = min((unsigned) entry->info.ping, (unsigned) pingtime);
+ serverreplycount++;
+ }
+
+ // other server info is updated by the caller
+ return n;
+}
+
+static void NetConn_ClientParsePacket_ServerList_UpdateCache(int n)
+{
+ serverlist_entry_t *entry = &serverlist_cache[n];
+ serverlist_info_t *info = &entry->info;
+ // update description strings for engine menu and console output
+ dpsnprintf(entry->line1, sizeof(serverlist_cache[n].line1), "^%c%5d^7 ^%c%3u^7/%3u %-65.65s", info->ping >= 300 ? '1' : (info->ping >= 200 ? '3' : '7'), (int)info->ping, ((info->numhumans > 0 && info->numhumans < info->maxplayers) ? (info->numhumans >= 4 ? '7' : '3') : '1'), info->numplayers, info->maxplayers, info->name);
+ dpsnprintf(entry->line2, sizeof(serverlist_cache[n].line2), "^4%-21.21s %-19.19s ^%c%-17.17s^4 %-20.20s", info->cname, info->game,
+ (
+ info->gameversion != gameversion.integer
+ &&
+ !(
+ gameversion_min.integer >= 0 // min/max range set by user/mod?
+ && gameversion_max.integer >= 0
+ && gameversion_min.integer <= info->gameversion // version of server in min/max range?
+ && gameversion_max.integer >= info->gameversion
+ )
+ ) ? '1' : '4',
+ info->mod, info->map);
+ if (entry->query == SQS_QUERIED)
+ {
+ if(!serverlist_paused)
+ ServerList_ViewList_Remove(entry);
+ }
+ // if not in the slist menu we should print the server to console (if wanted)
+ else if( serverlist_consoleoutput )
+ Con_Printf("%s\n%s\n", serverlist_cache[n].line1, serverlist_cache[n].line2);
+ // and finally, update the view set
+ if(!serverlist_paused)
+ ServerList_ViewList_Insert( entry );
+ // update the entry's state
+ serverlist_cache[n].query = SQS_QUERIED;
+}
+
+// returns true, if it's sensible to continue the processing
+static qbool NetConn_ClientParsePacket_ServerList_PrepareQuery( int protocol, const char *ipstring, qbool isfavorite ) {
+ int n;
+ serverlist_entry_t *entry;
+
+ // ignore the rest of the message if the serverlist is full
+ if( serverlist_cachecount == SERVERLIST_TOTALSIZE )
+ return false;
+ // also ignore it if we have already queried it (other master server response)
+ for( n = 0 ; n < serverlist_cachecount ; n++ )
+ if( !strcmp( ipstring, serverlist_cache[ n ].info.cname ) )
+ break;
+
+ if( n < serverlist_cachecount ) {
+ // the entry has already been queried once or
+ return true;
+ }
+
+ if (serverlist_maxcachecount <= n)
+ {
+ serverlist_maxcachecount += 64;
+ serverlist_cache = (serverlist_entry_t *)Mem_Realloc(netconn_mempool, (void *)serverlist_cache, sizeof(serverlist_entry_t) * serverlist_maxcachecount);
+ }
+
+ entry = &serverlist_cache[n];
+
+ memset(entry, 0, sizeof(*entry));
+ entry->protocol = protocol;
+ // store the data the engine cares about (address and ping)
+ strlcpy (entry->info.cname, ipstring, sizeof(entry->info.cname));
+
+ entry->info.isfavorite = isfavorite;
+
+ // no, then reset the ping right away
+ entry->info.ping = -1;
+ // we also want to increase the serverlist_cachecount then
+ serverlist_cachecount++;
+ serverquerycount++;
+
+ entry->query = SQS_QUERYING;
+
+ return true;
+}
+
+static void NetConn_ClientParsePacket_ServerList_ParseDPList(lhnetaddress_t *senderaddress, const unsigned char *data, int length, qbool isextended)
+{
+ masterreplycount++;
+ if (serverlist_consoleoutput)
+ Con_Printf("received DarkPlaces %sserver list...\n", isextended ? "extended " : "");
+ while (length >= 7)
+ {
+ char ipstring [128];
+
+ // IPv4 address
+ if (data[0] == '\\')
+ {
+ unsigned short port = data[5] * 256 + data[6];
+
+ if (port != 0 && (data[1] != 0xFF || data[2] != 0xFF || data[3] != 0xFF || data[4] != 0xFF))
+ dpsnprintf (ipstring, sizeof (ipstring), "%u.%u.%u.%u:%hu", data[1], data[2], data[3], data[4], port);
+
+ // move on to next address in packet
+ data += 7;
+ length -= 7;
+ }
+ // IPv6 address
+ else if (data[0] == '/' && isextended && length >= 19)
+ {
+ unsigned short port = data[17] * 256 + data[18];
+
+ if (port != 0)
+ {
+#ifdef WHY_JUST_WHY
+ const char *ifname;
+ char ifnamebuf[16];
+
+ /// \TODO: make some basic checks of the IP address (broadcast, ...)
+
+ ifname = LHNETADDRESS_GetInterfaceName(senderaddress, ifnamebuf, sizeof(ifnamebuf));
+ if (ifname != NULL)
+ {
+ dpsnprintf (ipstring, sizeof (ipstring), "[%x:%x:%x:%x:%x:%x:%x:%x%%%s]:%hu",
+ (data[1] << 8) | data[2], (data[3] << 8) | data[4], (data[5] << 8) | data[6], (data[7] << 8) | data[8],
+ (data[9] << 8) | data[10], (data[11] << 8) | data[12], (data[13] << 8) | data[14], (data[15] << 8) | data[16],
+ ifname, port);
+ }
+ else
+#endif
+ {
+ dpsnprintf (ipstring, sizeof (ipstring), "[%x:%x:%x:%x:%x:%x:%x:%x]:%hu",
+ (data[1] << 8) | data[2], (data[3] << 8) | data[4], (data[5] << 8) | data[6], (data[7] << 8) | data[8],
+ (data[9] << 8) | data[10], (data[11] << 8) | data[12], (data[13] << 8) | data[14], (data[15] << 8) | data[16],
+ port);
+ }
+ }
+
+ // move on to next address in packet
+ data += 19;
+ length -= 19;
+ }
+ else
+ {
+ Con_Print("Error while parsing the server list\n");
+ break;
+ }
+
+ if (serverlist_consoleoutput && developer_networking.integer)
+ Con_Printf("Requesting info from DarkPlaces server %s\n", ipstring);
+
+ if( !NetConn_ClientParsePacket_ServerList_PrepareQuery( PROTOCOL_DARKPLACES7, ipstring, false ) ) {
+ break;
+ }
+
+ }
+
+ // begin or resume serverlist queries
+ serverlist_querysleep = false;
+ serverlist_querywaittime = host.realtime + 3;
+}
+#endif
+
+static int NetConn_ClientParsePacket(lhnetsocket_t *mysocket, unsigned char *data, int length, lhnetaddress_t *peeraddress)
+{
+ qbool fromserver;
+ int ret, c;
+ char *string, addressstring2[128];