summaryrefslogtreecommitdiff
path: root/src/engine/serverbrowser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/serverbrowser.cpp')
-rw-r--r--src/engine/serverbrowser.cpp310
1 files changed, 88 insertions, 222 deletions
diff --git a/src/engine/serverbrowser.cpp b/src/engine/serverbrowser.cpp
index 85109bf..a839c35 100644
--- a/src/engine/serverbrowser.cpp
+++ b/src/engine/serverbrowser.cpp
@@ -4,15 +4,13 @@
#define PROTOCOL_VERSION 260 // bump when protocol changes, dpulicate
-struct resolverthread
-{
+struct resolverthread {
SDL_Thread *thread;
const char *query;
int starttime;
};
-struct resolverresult
-{
+struct resolverresult {
const char *query;
ENetAddress address;
};
@@ -26,28 +24,23 @@ SDL_cond *querycond, *resultcond;
#define RESOLVERTHREADS 2
#define RESOLVERLIMIT 3000
-int resolverloop(void * data)
-{
+int resolverloop(void * data) {
resolverthread *rt = (resolverthread *)data;
SDL_LockMutex(resolvermutex);
SDL_Thread *thread = rt->thread;
SDL_UnlockMutex(resolvermutex);
if(!thread || SDL_GetThreadID(thread) != SDL_ThreadID())
return 0;
- while(thread == rt->thread)
- {
+ while(thread == rt->thread) {
SDL_LockMutex(resolvermutex);
while(resolverqueries.empty()) SDL_CondWait(querycond, resolvermutex);
rt->query = resolverqueries.pop();
rt->starttime = totalmillis;
SDL_UnlockMutex(resolvermutex);
-
ENetAddress address = { ENET_HOST_ANY, ENET_PORT_ANY };
enet_address_set_host(&address, rt->query);
-
SDL_LockMutex(resolvermutex);
- if(rt->query && thread == rt->thread)
- {
+ if(rt->query && thread == rt->thread) {
resolverresult &rr = resolverresults.add();
rr.query = rt->query;
rr.address = address;
@@ -60,15 +53,12 @@ int resolverloop(void * data)
return 0;
}
-void resolverinit()
-{
+void resolverinit() {
resolvermutex = SDL_CreateMutex();
querycond = SDL_CreateCond();
resultcond = SDL_CreateCond();
-
SDL_LockMutex(resolvermutex);
- loopi(RESOLVERTHREADS)
- {
+ loopi(RESOLVERTHREADS) {
resolverthread &rt = resolverthreads.add();
rt.query = NULL;
rt.starttime = 0;
@@ -77,11 +67,9 @@ void resolverinit()
SDL_UnlockMutex(resolvermutex);
}
-void resolverstop(resolverthread &rt)
-{
+void resolverstop(resolverthread &rt) {
SDL_LockMutex(resolvermutex);
- if(rt.query)
- {
+ if(rt.query) {
#if SDL_VERSION_ATLEAST(2, 0, 2)
SDL_DetachThread(rt.thread);
#endif
@@ -92,47 +80,38 @@ void resolverstop(resolverthread &rt)
SDL_UnlockMutex(resolvermutex);
}
-void resolverclear()
-{
+void resolverclear() {
if(resolverthreads.empty()) return;
-
SDL_LockMutex(resolvermutex);
resolverqueries.shrink(0);
resolverresults.shrink(0);
- loopv(resolverthreads)
- {
+ loopv(resolverthreads) {
resolverthread &rt = resolverthreads[i];
resolverstop(rt);
}
SDL_UnlockMutex(resolvermutex);
}
-void resolverquery(const char *name)
-{
+void resolverquery(const char *name) {
if(resolverthreads.empty()) resolverinit();
-
SDL_LockMutex(resolvermutex);
resolverqueries.add(name);
SDL_CondSignal(querycond);
SDL_UnlockMutex(resolvermutex);
}
-bool resolvercheck(const char **name, ENetAddress *address)
-{
+bool resolvercheck(const char **name, ENetAddress *address) {
bool resolved = false;
SDL_LockMutex(resolvermutex);
- if(!resolverresults.empty())
- {
+ if(!resolverresults.empty()) {
resolverresult &rr = resolverresults.pop();
*name = rr.query;
address->host = rr.address.host;
resolved = true;
}
- else loopv(resolverthreads)
- {
+ else loopv(resolverthreads) {
resolverthread &rt = resolverthreads[i];
- if(rt.query && totalmillis - rt.starttime > RESOLVERLIMIT)
- {
+ if(rt.query && totalmillis - rt.starttime > RESOLVERLIMIT) {
resolverstop(rt);
*name = rt.query;
resolved = true;
@@ -142,39 +121,31 @@ bool resolvercheck(const char **name, ENetAddress *address)
return resolved;
}
-bool resolverwait(const char *name, ENetAddress *address)
-{
+bool resolverwait(const char *name, ENetAddress *address) {
if(resolverthreads.empty()) resolverinit();
-
defformatstring(text, "resolving %s... (esc to abort)", name);
renderprogress(0, text);
-
SDL_LockMutex(resolvermutex);
resolverqueries.add(name);
SDL_CondSignal(querycond);
int starttime = SDL_GetTicks(), timeout = 0;
bool resolved = false;
- for(;;)
- {
+ for(;;) {
SDL_CondWaitTimeout(resultcond, resolvermutex, 250);
- loopv(resolverresults) if(resolverresults[i].query == name)
- {
+ loopv(resolverresults) if(resolverresults[i].query == name) {
address->host = resolverresults[i].address.host;
resolverresults.remove(i);
resolved = true;
break;
}
if(resolved) break;
-
timeout = SDL_GetTicks() - starttime;
renderprogress(min(float(timeout)/RESOLVERLIMIT, 1.0f), text);
if(interceptkey(SDLK_ESCAPE)) timeout = RESOLVERLIMIT + 1;
if(timeout > RESOLVERLIMIT) break;
}
- if(!resolved && timeout > RESOLVERLIMIT)
- {
- loopv(resolverthreads)
- {
+ if(!resolved && timeout > RESOLVERLIMIT) {
+ loopv(resolverthreads) {
resolverthread &rt = resolverthreads[i];
if(rt.query == name) { resolverstop(rt); break; }
}
@@ -185,24 +156,19 @@ bool resolverwait(const char *name, ENetAddress *address)
#define CONNLIMIT 20000
-int connectwithtimeout(ENetSocket sock, const char *hostname, const ENetAddress &address)
-{
+int connectwithtimeout(ENetSocket sock, const char *hostname, const ENetAddress &address) {
defformatstring(text, "connecting to %s... (esc to abort)", hostname);
renderprogress(0, text);
-
ENetSocketSet readset, writeset;
- if(!enet_socket_connect(sock, &address)) for(int starttime = SDL_GetTicks(), timeout = 0; timeout <= CONNLIMIT;)
- {
+ if(!enet_socket_connect(sock, &address)) for(int starttime = SDL_GetTicks(), timeout = 0; timeout <= CONNLIMIT;) {
ENET_SOCKETSET_EMPTY(readset);
ENET_SOCKETSET_EMPTY(writeset);
ENET_SOCKETSET_ADD(readset, sock);
ENET_SOCKETSET_ADD(writeset, sock);
int result = enet_socketset_select(sock, &readset, &writeset, 250);
if(result < 0) break;
- else if(result > 0)
- {
- if(ENET_SOCKETSET_CHECK(readset, sock) || ENET_SOCKETSET_CHECK(writeset, sock))
- {
+ else if(result > 0) {
+ if(ENET_SOCKETSET_CHECK(readset, sock) || ENET_SOCKETSET_CHECK(writeset, sock)) {
int error = 0;
if(enet_socket_get_option(sock, ENET_SOCKOPT_ERROR, &error) < 0 || error) break;
return 0;
@@ -212,45 +178,30 @@ int connectwithtimeout(ENetSocket sock, const char *hostname, const ENetAddress
renderprogress(min(float(timeout)/CONNLIMIT, 1.0f), text);
if(interceptkey(SDLK_ESCAPE)) break;
}
-
return -1;
}
-struct pingattempts
-{
+struct pingattempts {
enum { MAXATTEMPTS = 2 };
-
int offset, attempts[MAXATTEMPTS];
-
pingattempts() : offset(0) { clearattempts(); }
-
void clearattempts() { memset(attempts, 0, sizeof(attempts)); }
-
void setoffset() { offset = 1 + rnd(0xFFFFFF); }
-
- int encodeping(int millis)
- {
+ int encodeping(int millis) {
millis += offset;
return millis ? millis : 1;
}
-
- int decodeping(int val)
- {
+ int decodeping(int val) {
return val - offset;
}
-
- int addattempt(int millis)
- {
+ int addattempt(int millis) {
int val = encodeping(millis);
loopk(MAXATTEMPTS-1) attempts[k+1] = attempts[k];
attempts[0] = val;
return val;
}
-
- bool checkattempt(int val, bool del = true)
- {
- if(val) loopk(MAXATTEMPTS) if(attempts[k] == val)
- {
+ bool checkattempt(int val, bool del = true) {
+ if(val) loopk(MAXATTEMPTS) if(attempts[k] == val) {
if(del) attempts[k] = 0;
return true;
}
@@ -261,15 +212,11 @@ struct pingattempts
enum { UNRESOLVED = 0, RESOLVING, RESOLVED };
-struct serverinfo : pingattempts
-{
- enum
- {
+struct serverinfo : pingattempts {
+ enum {
WAITING = INT_MAX,
-
MAXPINGS = 3
};
-
string name, map, sdesc;
int port, numplayers, resolved, ping, lastping, nextping;
int pings[MAXPINGS];
@@ -277,65 +224,47 @@ struct serverinfo : pingattempts
ENetAddress address;
bool keep;
const char *password;
-
serverinfo()
- : port(-1), numplayers(0), resolved(UNRESOLVED), keep(false), password(NULL)
- {
+ : port(-1), numplayers(0), resolved(UNRESOLVED), keep(false), password(NULL) {
name[0] = map[0] = sdesc[0] = '\0';
clearpings();
setoffset();
}
-
- ~serverinfo()
- {
+ ~serverinfo() {
DELETEA(password);
}
-
- void clearpings()
- {
+ void clearpings() {
ping = WAITING;
loopk(MAXPINGS) pings[k] = WAITING;
nextping = 0;
lastping = -1;
clearattempts();
}
-
- void cleanup()
- {
+ void cleanup() {
clearpings();
attr.setsize(0);
numplayers = 0;
}
-
- void reset()
- {
+ void reset() {
lastping = -1;
}
-
- void checkdecay(int decay)
- {
+ void checkdecay(int decay) {
if(lastping >= 0 && totalmillis - lastping >= decay)
cleanup();
if(lastping < 0) lastping = totalmillis;
}
-
- void calcping()
- {
+ void calcping() {
int numpings = 0, totalpings = 0;
loopk(MAXPINGS) if(pings[k] != WAITING) { totalpings += pings[k]; numpings++; }
ping = numpings ? totalpings/numpings : WAITING;
}
-
- void addping(int rtt, int millis)
- {
+ void addping(int rtt, int millis) {
if(millis >= lastping) lastping = -1;
pings[nextping] = rtt;
nextping = (nextping+1)%MAXPINGS;
calcping();
}
-
- static bool compare(serverinfo *a, serverinfo *b)
- {
+ static bool compare(serverinfo *a, serverinfo *b) {
bool ac = (a->attr.length() != 0) && (a->attr[0]==PROTOCOL_VERSION);
bool bc = (b->attr.length() != 0) && (b->attr[0]==PROTOCOL_VERSION);
if(ac > bc) return true;
@@ -358,36 +287,27 @@ vector<serverinfo *> servers;
ENetSocket pingsock = ENET_SOCKET_NULL;
int lastinfo = 0;
-static serverinfo *newserver(const char *name, int port, uint ip = ENET_HOST_ANY)
-{
+static serverinfo *newserver(const char *name, int port, uint ip = ENET_HOST_ANY) {
serverinfo *si = new serverinfo;
si->address.host = ip;
si->address.port = server::serverinfoport(port);
if(ip!=ENET_HOST_ANY) si->resolved = RESOLVED;
-
si->port = port;
if(name) copystring(si->name, name);
- else if(ip==ENET_HOST_ANY || enet_address_get_host_ip(&si->address, si->name, sizeof(si->name)) < 0)
- {
+ else if(ip==ENET_HOST_ANY || enet_address_get_host_ip(&si->address, si->name, sizeof(si->name)) < 0) {
delete si;
return NULL;
-
}
-
servers.add(si);
-
return si;
}
-void addserver(const char *name, int port, const char *password, bool keep)
-{
+void addserver(const char *name, int port, const char *password, bool keep) {
if(port <= 0) port = server::serverport();
- loopv(servers)
- {
+ loopv(servers) {
serverinfo *s = servers[i];
if(strcmp(s->name, name) || s->port != port) continue;
- if(password && (!s->password || strcmp(s->password, password)))
- {
+ if(password && (!s->password || strcmp(s->password, password))) {
DELETEA(s->password);
s->password = newstring(password);
}
@@ -407,47 +327,37 @@ VARP(maxservpings, 0, 10, 1000);
pingattempts lanpings;
-template<size_t N> static inline void buildping(ENetBuffer &buf, uchar (&ping)[N], pingattempts &a)
-{
+template<size_t N> static inline void buildping(ENetBuffer &buf, uchar (&ping)[N], pingattempts &a) {
ucharbuf p(ping, N);
putint(p, a.addattempt(totalmillis));
buf.data = ping;
buf.dataLength = p.length();
}
-void pingservers()
-{
- if(pingsock == ENET_SOCKET_NULL)
- {
+void pingservers() {
+ if(pingsock == ENET_SOCKET_NULL) {
pingsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM);
- if(pingsock == ENET_SOCKET_NULL)
- {
+ if(pingsock == ENET_SOCKET_NULL) {
lastinfo = totalmillis;
return;
}
enet_socket_set_option(pingsock, ENET_SOCKOPT_NONBLOCK, 1);
enet_socket_set_option(pingsock, ENET_SOCKOPT_BROADCAST, 1);
-
lanpings.setoffset();
}
-
ENetBuffer buf;
uchar ping[MAXTRANS];
-
static int lastping = 0;
if(lastping >= servers.length()) lastping = 0;
- loopi(maxservpings ? min(servers.length(), maxservpings) : servers.length())
- {
+ loopi(maxservpings ? min(servers.length(), maxservpings) : servers.length()) {
serverinfo &si = *servers[lastping];
if(++lastping >= servers.length()) lastping = 0;
if(si.address.host == ENET_HOST_ANY) continue;
buildping(buf, ping, si);
enet_socket_send(pingsock, &si.address, &buf, 1);
-
si.checkdecay(servpingdecay);
}
- if(searchlan)
- {
+ if(searchlan) {
ENetAddress address;
address.host = ENET_HOST_BROADCAST;
address.port = server::laninfoport();
@@ -457,31 +367,24 @@ void pingservers()
lastinfo = totalmillis;
}
-void checkresolver()
-{
+void checkresolver() {
int resolving = 0;
- loopv(servers)
- {
+ loopv(servers) {
serverinfo &si = *servers[i];
if(si.resolved == RESOLVED) continue;
- if(si.address.host == ENET_HOST_ANY)
- {
+ if(si.address.host == ENET_HOST_ANY) {
if(si.resolved == UNRESOLVED) { si.resolved = RESOLVING; resolverquery(si.name); }
resolving++;
}
}
if(!resolving) return;
-
const char *name = NULL;
- for(;;)
- {
+ for(;;) {
ENetAddress addr = { ENET_HOST_ANY, ENET_PORT_ANY };
if(!resolvercheck(&name, &addr)) break;
- loopv(servers)
- {
+ loopv(servers) {
serverinfo &si = *servers[i];
- if(name == si.name)
- {
+ if(name == si.name) {
si.resolved = RESOLVED;
si.address.host = addr.host;
break;
@@ -492,8 +395,7 @@ void checkresolver()
static int lastreset = 0;
-void checkpings()
-{
+void checkpings() {
if(pingsock==ENET_SOCKET_NULL) return;
enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
ENetBuffer buf;
@@ -502,22 +404,19 @@ void checkpings()
char text[MAXTRANS];
buf.data = ping;
buf.dataLength = sizeof(ping);
- while(enet_socket_wait(pingsock, &events, 0) >= 0 && events)
- {
+ while(enet_socket_wait(pingsock, &events, 0) >= 0 && events) {
int len = enet_socket_receive(pingsock, &addr, &buf, 1);
if(len <= 0) return;
ucharbuf p(ping, len);
int millis = getint(p);
serverinfo *si = NULL;
loopv(servers) if(addr.host == servers[i]->address.host && addr.port == servers[i]->address.port) { si = servers[i]; break; }
- if(si)
- {
+ if(si) {
if(!si->checkattempt(millis)) continue;
millis = si->decodeping(millis);
}
else if(!searchlan || !lanpings.checkattempt(millis, false)) continue;
- else
- {
+ else {
si = newserver(NULL, server::serverport(addr.port), addr.host);
millis = lanpings.decodeping(millis);
}
@@ -534,8 +433,7 @@ void checkpings()
}
}
-void sortservers()
-{
+void sortservers() {
servers.sort(serverinfo::compare);
}
COMMAND(sortservers, "");
@@ -543,17 +441,14 @@ COMMAND(sortservers, "");
VARP(autosortservers, 0, 1, 1);
VARP(autoupdateservers, 0, 1, 1);
-void refreshservers()
-{
+void refreshservers() {
static int lastrefresh = 0;
if(lastrefresh==totalmillis) return;
- if(totalmillis - lastrefresh > 1000)
- {
+ if(totalmillis - lastrefresh > 1000) {
loopv(servers) servers[i]->reset();
lastreset = totalmillis;
}
lastrefresh = totalmillis;
-
checkresolver();
checkpings();
if(totalmillis - lastinfo >= servpingrate/(maxservpings ? max(1, (servers.length() + maxservpings - 1) / maxservpings) : 1)) pingservers();
@@ -562,26 +457,21 @@ void refreshservers()
serverinfo *selectedserver = NULL;
-const char *showservers(g3d_gui *cgui, uint *header, int pagemin, int pagemax)
-{
+const char *showservers(g3d_gui *cgui, uint *header, int pagemin, int pagemax) {
refreshservers();
- if(servers.empty())
- {
+ if(servers.empty()) {
if(header) execute(header);
return NULL;
}
serverinfo *sc = NULL;
- for(int start = 0; start < servers.length();)
- {
+ for(int start = 0; start < servers.length();) {
if(start > 0) cgui->tab();
if(header) execute(header);
int end = servers.length();
cgui->pushlist();
- loopi(10)
- {
+ loopi(10) {
if(!game::serverinfostartcolumn(cgui, i)) break;
- for(int j = start; j < end; j++)
- {
+ for(int j = start; j < end; j++) {
if(!i && j+1 - start >= pagemin && (j+1 - start >= pagemax || cgui->shouldtab())) { end = j; break; }
serverinfo &si = *servers[j];
const char *sdesc = si.sdesc;
@@ -600,8 +490,7 @@ const char *showservers(g3d_gui *cgui, uint *header, int pagemin, int pagemax)
return "connectselected";
}
-void connectselected()
-{
+void connectselected() {
if(!selectedserver) return;
connectserv(selectedserver->name, selectedserver->port, selectedserver->password);
selectedserver = NULL;
@@ -609,8 +498,7 @@ void connectselected()
COMMAND(connectselected, "");
-void clearservers(bool full = false)
-{
+void clearservers(bool full = false) {
resolverclear();
if(full) servers.deletecontents();
else loopvrev(servers) if(!servers[i]->keep) delete servers.remove(i);
@@ -619,24 +507,19 @@ void clearservers(bool full = false)
#define RETRIEVELIMIT 20000
-void retrieveservers(vector<char> &data)
-{
+void retrieveservers(vector<char> &data) {
ENetSocket sock = connectmaster(true);
if(sock == ENET_SOCKET_NULL) return;
-
extern char *mastername;
defformatstring(text, "retrieving servers from %s... (esc to abort)", mastername);
renderprogress(0, text);
-
int starttime = SDL_GetTicks(), timeout = 0;
const char *req = "list\n";
int reqlen = strlen(req);
ENetBuffer buf;
- while(reqlen > 0)
- {
+ while(reqlen > 0) {
enet_uint32 events = ENET_SOCKET_WAIT_SEND;
- if(enet_socket_wait(sock, &events, 250) >= 0 && events)
- {
+ if(enet_socket_wait(sock, &events, 250) >= 0 && events) {
buf.data = (void *)req;
buf.dataLength = reqlen;
int sent = enet_socket_send(sock, NULL, &buf, 1);
@@ -650,12 +533,9 @@ void retrieveservers(vector<char> &data)
if(interceptkey(SDLK_ESCAPE)) timeout = RETRIEVELIMIT + 1;
if(timeout > RETRIEVELIMIT) break;
}
-
- if(reqlen <= 0) for(;;)
- {
+ if(reqlen <= 0) for(;;) {
enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
- if(enet_socket_wait(sock, &events, 250) >= 0 && events)
- {
+ if(enet_socket_wait(sock, &events, 250) >= 0 && events) {
if(data.length() >= data.capacity()) data.reserve(4096);
buf.data = data.getbuf() + data.length();
buf.dataLength = data.capacity() - data.length();
@@ -668,39 +548,31 @@ void retrieveservers(vector<char> &data)
if(interceptkey(SDLK_ESCAPE)) timeout = RETRIEVELIMIT + 1;
if(timeout > RETRIEVELIMIT) break;
}
-
if(data.length()) data.add('\0');
enet_socket_destroy(sock);
}
bool updatedservers = false;
-void updatefrommaster()
-{
+void updatefrommaster() {
vector<char> data;
retrieveservers(data);
if(data.empty()) conoutf(CON_ERROR, "master server not replying");
- else
- {
+ else {
clearservers();
char *line = data.getbuf();
- while(char *end = (char *)memchr(line, '\n', data.length() - (line - data.getbuf())))
- {
+ while(char *end = (char *)memchr(line, '\n', data.length() - (line - data.getbuf()))) {
*end = '\0';
-
const char *args = line;
while(args < end && !iscubespace(*args)) args++;
int cmdlen = args - line;
while(args < end && iscubespace(*args)) args++;
-
- if(matchstring(line, cmdlen, "addserver"))
- {
+ if(matchstring(line, cmdlen, "addserver")) {
string ip;
int port;
if(sscanf(args, "%100s %d", ip, &port) == 2) addserver(ip, port);
}
else if(matchstring(line, cmdlen, "echo")) conoutf("\f1%s", args);
-
line = end + 1;
}
}
@@ -708,8 +580,7 @@ void updatefrommaster()
updatedservers = true;
}
-void initservers()
-{
+void initservers() {
selectedserver = NULL;
if(autoupdateservers && !updatedservers) updatefrommaster();
}
@@ -720,17 +591,14 @@ ICOMMAND(clearservers, "i", (int *full), clearservers(*full!=0));
COMMAND(updatefrommaster, "");
COMMAND(initservers, "");
-void writeservercfg()
-{
+void writeservercfg() {
if(!game::savedservers()) return;
stream *f = openutf8file(path(game::savedservers(), true), "w");
if(!f) return;
int kept = 0;
- loopv(servers)
- {
+ loopv(servers) {
serverinfo *s = servers[i];
- if(s->keep)
- {
+ if(s->keep) {
if(!kept) f->printf("// servers that should never be cleared from the server list\n\n");
if(s->password) f->printf("keepserver %s %d %s\n", escapeid(s->name), s->port, escapestring(s->password));
else f->printf("keepserver %s %d\n", escapeid(s->name), s->port);
@@ -739,11 +607,9 @@ void writeservercfg()
}
if(kept) f->printf("\n");
f->printf("// servers connected to are added here automatically\n\n");
- loopv(servers)
- {
+ loopv(servers) {
serverinfo *s = servers[i];
- if(!s->keep)
- {
+ if(!s->keep) {
if(s->password) f->printf("addserver %s %d %s\n", escapeid(s->name), s->port, escapestring(s->password));
else f->printf("addserver %s %d\n", escapeid(s->name), s->port);
}