void AddToFileSource(source_data *source, server_data *serv) { if (IsInSource(source, serv)) return; SB_ServerList_Lock(); // reallocate buffer if we've run out of space if (source->serversn >= source->servers_allocated) { int new_size = source->servers_allocated + 4; server_data** newlist = Q_malloc(new_size * sizeof(server_data*)); memcpy(newlist, source->servers, sizeof(server_data*) * source->servers_allocated); Q_free(source->servers); source->servers = newlist; source->servers_allocated = new_size; } source->servers[source->serversn++] = Clone_Server(serv); rebuild_servers_list = true; SB_ServerList_Unlock(); DumpSource(source); Mark_Source(sources[0]); }
void Rebuild_Servers_List(void) { int i; int suppressed_servers = 0; int server_limit = sizeof(servers) / sizeof(servers[0]); serversn = 0; rebuild_servers_list = 0; SB_ServerList_Lock(); for (i=0; i < sourcesn; i++) { if (sources[i]->checked) { int j; for (j=0; j < sources[i]->serversn; j++) { int k; qbool found_duplicate = false; if (sources[i]->servers[j] == NULL) continue; // Try and find a matching address for (k = 0; k < serversn && k < server_limit; k++) { if (!memcmp(&(servers[k]->address), &(sources[i]->servers[j]->address), sizeof(netadr_t))) { found_duplicate = true; break; } } if (! found_duplicate) { // if not on list yet if (serversn < server_limit) { if (sources[i]->servers[j]->ping < -1) serversn = serversn; servers[serversn++] = sources[i]->servers[j]; } else { ++suppressed_servers; } } } } } resort_servers = 1; rebuild_all_players = 1; Servers_pos = 0; serversn_passed = serversn; SB_ServerList_Unlock(); }
static void SB_PingTree_AddNodes(void) { int i; // add our neighbours - servers we directly ping SB_ServerList_Lock(); ping_nodes[startnode_id].nlist_start = ping_neighbours_count; for (i = 0; i < serversn; i++) { SB_PingTree_AddServer(servers[i]); } ping_nodes[startnode_id].nlist_end = ping_neighbours_count; SB_ServerList_Unlock(); }
static void SB_PingTree_UpdateServerList(void) { int i; SB_ServerList_Lock(); for (i = 0; i < serversn; i++) { nodeid_t id = SB_PingTree_FindIp(SB_Netaddr2Ipaddr(&servers[i]->address)); if (id == INVALID_NODE || ping_nodes[id].prev == INVALID_NODE || ping_nodes[id].prev == startnode_id) continue; SB_Server_SetBestPing(servers[i], ping_nodes[id].dist); } SB_ServerList_Unlock(); }
void Reload_Sources(void) { int i; vfsfile_t *f; char ln[2048]; source_data *s; SB_ServerList_Lock(); for (i=0; i < sourcesn; i++) Delete_Source(sources[i]); sourcesn = 0; // create dummy unbound source sources[0] = Create_Source(); sources[0]->type = type_dummy; strlcpy (sources[0]->name, "Unbound", sizeof (sources[0]->name)); sources[0]->servers = (server_data **) Q_malloc(MAX_UNBOUND*sizeof(server_data *)); sources[0]->serversn = 0; sources[0]->servers_allocated = MAX_UNBOUND; sourcesn = 1; f = FS_OpenVFS(SOURCES_LIST_FILENAME, "rb", FS_ANY); if (!f) { //Com_Printf ("sources file not found: %s\n", SOURCES_PATH); SB_ServerList_Unlock(); return; } s = Create_Source(); while (VFS_GETS(f, ln, sizeof(ln))) { char line[2048]; char *p, *q; if (sscanf(ln, "%[ -~ ]s", line) != 1) { continue; } p = next_nonspace(line); if (*p == '/') continue; // comment q = next_space(p); if (!strncmp(p, "master", q-p)) { s->type = type_master; } else if (!strncmp(p, "file", q-p)) { s->type = type_file; } else if (!strncmp(p, "url", q-p)) { s->type = type_url; } else { continue; } p = next_nonspace(q); q = (*p == '\"') ? next_quote(++p) : next_space(p); if (q-p <= 0) continue; strlcpy (s->name, p, min(q-p+1, MAX_SOURCE_NAME+1)); p = next_nonspace(q+1); q = next_space(p); *q = 0; if (q-p <= 0) continue; if (s->type == type_file) strlcpy (s->address.filename, p, sizeof (s->address.filename)); else if (s->type == type_url) strlcpy (s->address.url, p, sizeof (s->address.url)); else if (!NET_StringToAdr(p, &(s->address.address))) continue; sources[sourcesn] = Create_Source(); i = sources[sourcesn]->unique; memcpy(sources[sourcesn], s, sizeof(source_data)); sources[sourcesn]->unique = i; sourcesn++; } Delete_Source(s); VFS_CLOSE(f); //Com_Printf("Read %d sources for Server Browser\n", sourcesn); // update all file sources for (i=0; i < sourcesn; i++) if (sources[i]->type == type_file) Update_Source(sources[i]); else if (sources[i]->type == type_master || sources[i]->type == type_url) Precache_Source(sources[i]); rebuild_servers_list = 1; resort_sources = 1; SB_ServerList_Unlock(); }
DWORD WINAPI Update_Multiple_Sources_Proc(void * lpParameter) { // get servers from master server SYSTEMTIME lt; char request[] = {'c', '\n', '\0'}; socket_t newsocket; struct sockaddr_storage server; int ret = 0, i, sourcenum; unsigned char answer[10000]; fd_set fd; struct timeval tv; int total_masters = 0; int updated = 0; int d1, d2; GetLocalTime(<); d1 = lt.wSecond + 60*(lt.wMinute + 60*(lt.wHour + 24*(lt.wDay))); // update file sources - this should be a flash for (sourcenum = 0; sourcenum < psourcesn; sourcenum++) if (psources[sourcenum]->checked) { if (psources[sourcenum]->type == type_file) Update_Source(psources[sourcenum]); if (psources[sourcenum]->type == type_url) Update_Source(psources[sourcenum]); // todo cache this too else if (psources[sourcenum]->type == type_master) { source_data *s = psources[sourcenum]; if (s->last_update.wYear != 0 && !source_full_update) { d2 = s->last_update.wSecond + 60*(s->last_update.wMinute + 60*(s->last_update.wHour + 24*(s->last_update.wDay))); if (d1 > d2 && d1 < d2 + sb_sourcevalidity.value*60) continue; } total_masters++; } } // update master sources newsocket = UDP_OpenSocket(PORT_ANY); for (sourcenum = 0; sourcenum < psourcesn && !abort_ping; sourcenum++) { server_data *servers[MAX_SERVERS]; int serversn = 0; int trynum = 0; source_data *s = psources[sourcenum]; double timeout; if (psources[sourcenum]->type != type_master || !psources[sourcenum]->checked) continue; if (s->last_update.wYear != 0 && !source_full_update) { d2 = s->last_update.wSecond + 60*(s->last_update.wMinute + 60*(s->last_update.wHour + 24*(s->last_update.wDay))); if (d1 > d2 && d1 < d2 + sb_sourcevalidity.value*60) continue; } // send trynum queries to master server for (trynum=0; trynum < sb_masterretries.value; trynum++) { NetadrToSockadr (&(s->address.address), &server); ret = sendto (newsocket, request, sizeof(request), 0, (struct sockaddr *)&server, sizeof(server) ); } if (ret <= 0) continue; timeout = Sys_DoubleTime() + (sb_mastertimeout.value / 1000.0); while (Sys_DoubleTime() < timeout) { struct sockaddr_storage hostaddr; netadr_t from; //fd.fd_count = 1; //fd.fd_array[0] = newsocket; FD_ZERO(&fd); FD_SET(newsocket, &fd); tv.tv_sec = 0; tv.tv_usec = 1000 * sb_mastertimeout.value; ret = select(newsocket+1, &fd, NULL, NULL, &tv); // get answer i = sizeof(hostaddr); if (ret > 0) ret = recvfrom (newsocket, (char *) answer, 10000, 0, (struct sockaddr *)&hostaddr, (socklen_t *)&i); if (ret > 0 && ret < 10000) { SockadrToNetadr (&hostaddr, &from); if (from.ip[0] == s->address.address.ip[0] && from.ip[1] == s->address.address.ip[1] && from.ip[2] == s->address.address.ip[2] && from.ip[3] == s->address.address.ip[3] && from.port == s->address.address.port) { answer[ret] = 0; if (memcmp(answer, "\xff\xff\xff\xff\x64\x0a", 6)) { continue; } // create servers avoiding duplicates for (i=6; i+5 < ret; i+=6) { char buf[32]; server_data* server; qbool exists = false; int j; snprintf(buf, sizeof (buf), "%u.%u.%u.%u:%u", (int)answer[i+0], (int)answer[i+1], (int)answer[i+2], (int)answer[i+3], 256 * (int)answer[i+4] + (int)answer[i+5]); server = Create_Server(buf); for (j=0; j<serversn; j++) { if (NET_CompareAdr(servers[j]->address, server->address)) { exists = true; break; } } if (!exists) servers[serversn++] = server; else Delete_Server(server); } } } } // copy all servers to source list if (serversn > 0) { updated++; SB_ServerList_Lock(); Reset_Source(s); s->servers = (server_data **) Q_malloc(serversn * sizeof(server_data *)); for (i=0; i < serversn; i++) s->servers[i] = servers[i]; s->serversn = serversn; s->servers_allocated = serversn; if (s->checked) rebuild_servers_list = 1; GetLocalTime(&(s->last_update)); SB_ServerList_Unlock(); if (sb_mastercache.value) DumpSource(s); } ping_pos = updated / (double)total_masters; } closesocket(newsocket); // Not having this here leads to crash almost always when some // other action with servers list happens right after this function. // Even 1 ms delay was enough during the tests, previously 500 ms was used. //Sys_MSleep(100); updating_sources = 0; sb_queuedtriggers |= SB_TRIGGER_SOURCESUPDATED; return 0; }
void Update_Source(source_data *s) { int i; qbool should_dump = false; server_data *servers[MAX_SERVERS]; int serversn = 0; if (s->type == type_dummy) return; if (s->type == type_file) { // read servers from file char name[1024]; snprintf(name, sizeof (name), "sb/%s", s->address.filename); should_dump = Update_Source_From_File(s, name, servers, &serversn); GetLocalTime(&(s->last_update)); } if (s->type == type_url) { SB_Update_Source_From_URL(s, servers, &serversn); } if (s->type == type_master) { // get servers from master server char request[] = {'c', '\n', '\0'}; socket_t newsocket; struct sockaddr_storage server; int ret = 0, i; unsigned char answer[10000]; fd_set fd; struct timeval tv; int trynum; int timeout; newsocket = UDP_OpenSocket(PORT_ANY); // so we have a socket // send status request for (trynum=0; trynum < sb_masterretries.value; trynum++) { NetadrToSockadr (&(s->address.address), &server); ret = sendto (newsocket, request, sizeof(request), 0, (struct sockaddr *)&server, sizeof(server) ); } if (ret < 0) return; timeout = Sys_DoubleTime() + (sb_mastertimeout.value / 1000.0); while (Sys_DoubleTime() < timeout) { //fd.fd_count = 1; //fd.fd_array[0] = newsocket; FD_ZERO(&fd); FD_SET(newsocket, &fd); tv.tv_sec = 0; tv.tv_usec = 1000 * 1.5 * sb_mastertimeout.value; // multiply timeout by 1.5 ret = select(newsocket+1, &fd, NULL, NULL, &tv); // get answer if (ret > 0) ret = recvfrom (newsocket, (char *) answer, 10000, 0, NULL, NULL); if (ret > 0 && ret < 10000) { answer[ret] = 0; if (memcmp(answer, "\xff\xff\xff\xff\x64\x0a", 6)) { closesocket(newsocket); return; } // create servers avoiding duplicates for (i=6; i+5 < ret; i+=6) { char buf[32]; server_data* server; qbool exists = false; int j; snprintf(buf, sizeof (buf), "%u.%u.%u.%u:%u", (int)answer[i+0], (int)answer[i+1], (int)answer[i+2], (int)answer[i+3], 256 * (int)answer[i+4] + (int)answer[i+5]); server = Create_Server(buf); for (j=0; j<serversn; j++) { if (NET_CompareAdr(servers[j]->address, server->address)) { exists = true; break; } } if (!exists) servers[serversn++] = server; else Delete_Server(server); } } } closesocket(newsocket); } SB_ServerList_Lock(); // copy all servers to source list if (serversn > 0) { Reset_Source(s); s->servers = (server_data **) Q_malloc((serversn + (s->type==type_file ? MAX_UNBOUND : 0)) * sizeof(server_data *)); for (i=0; i < serversn; i++) s->servers[i] = servers[i]; s->serversn = serversn; s->servers_allocated = serversn + (s->type == type_file ? MAX_UNBOUND : 0); if (s->checked) rebuild_servers_list = 1; if (sb_mastercache.value) { DumpSource(s); should_dump = false; } GetLocalTime(&(s->last_update)); } else if (s->type == type_file) { Reset_Source(s); s->servers = (server_data **) Q_malloc((serversn + (s->type==type_file ? MAX_UNBOUND : 0)) * sizeof(server_data *)); } SB_ServerList_Unlock(); if (should_dump) DumpSource(s); //Com_Printf ("Updating %15.15s: %d servers\n", s->name, serversn); }