allow to set an alternate game id in master server list

some games are known to support multiple protocols, when
you fetch a web list of server, it's good to be able to
enforce which alternative protocol must be used to query
the servers from this specific list

this functionnality is currently only supported in hard
coded list of masters, the GUI does not allow to set
the alternative query protocol when adding a master server
by hand or a server by hand, by the way user config files
can be edited to reflect that

you can set an alternate this way (using a pipe as separator):

ADD AMS|GPS http://www.qtracker.com/server_list_details.php?game=armyoperations qtracker.com

server fetched by this master server will be queried using the
gamespy GPS protocol instead of the AMS one, but they will be
considered as AMS games

it prevents some games to answer strings like:

> what broken query tool do you use?

because basically some version grok an old protocol
but other versions only grok the gamespy one: if the
server is listed in a gamespy master server, always
query it using the gamespy server protocol
master
Thomas Debesse 2018-03-24 23:10:19 +01:00
parent bbfdb6e4f6
commit 2b4483a12e
8 changed files with 140 additions and 49 deletions

View File

@ -100,7 +100,8 @@ static void master_okbutton_callback (GtkWidget *widget, GtkWidget* window) {
return;
}
master_to_add = add_master (master_addr_result, master_name_result, master_type, NULL, TRUE, FALSE);
// FIXME: gui does not allow to set server_query_type (defaults here as UNKNOWN_SERVER)
master_to_add = add_master (master_addr_result, master_name_result, master_type, UNKNOWN_SERVER, NULL, TRUE, FALSE);
if (!master_to_add) {
dialog_ok (NULL, _("Master address \"%s\" is not valid."),
master_addr_result);

View File

@ -115,6 +115,7 @@ struct server {
int ref_count;
enum server_type type;
enum server_type server_query_type;
unsigned short port;
unsigned short maxplayers;
@ -135,7 +136,8 @@ struct userver {
struct server *s;
int ref_count;
unsigned short port;
unsigned char type; // enum server_type type;
enum server_type type; // enum server_type type;
enum server_type server_query_type; // enum server_type type;
};
typedef struct {
@ -146,6 +148,7 @@ typedef struct {
typedef struct master {
char *name;
enum server_type type;
enum server_type server_query_type;
int isgroup; // is it a real master or master group?
int user; // is it added or edited by user?
QFMasterOptions options;

View File

@ -116,7 +116,7 @@ static int ottd_exec (const struct condef *con, int forkit);
static GList *quake_custom_cfgs (struct game* this, const char *path, const char *mod);
static void quake_save_info (FILE *f, struct server *s);
static void save_server_info (FILE *f, struct server *s);
char **get_custom_arguments(enum server_type type, const char *gamestring);
@ -3599,7 +3599,7 @@ static void quake_save_server_rules (FILE *f, struct server *s) {
}
static void quake_save_info (FILE *f, struct server *s) {
static void save_server_info (FILE *f, struct server *s) {
struct player *p;
GSList *list;
@ -3615,7 +3615,7 @@ static void quake_save_info (FILE *f, struct server *s) {
case Q1_SERVER:
case H2_SERVER:
fprintf (f,
"%s" QSTAT_DELIM_STR
"%s%s%s" QSTAT_DELIM_STR
"%s:%d" QSTAT_DELIM_STR
"%s" QSTAT_DELIM_STR
"%s:%d" QSTAT_DELIM_STR
@ -3626,6 +3626,8 @@ static void quake_save_info (FILE *f, struct server *s) {
"%d" QSTAT_DELIM_STR
"%d\n",
games[s->type].id,
s->server_query_type != UNKNOWN_SERVER? "|" : "",
s->server_query_type != UNKNOWN_SERVER? games[s->server_query_type].id : "",
inet_ntoa (s->host->ip), s->port,
(s->name)? s->name : "",
inet_ntoa (s->host->ip), s->port,
@ -3640,7 +3642,7 @@ static void quake_save_info (FILE *f, struct server *s) {
default:
fprintf (f,
"%s" QSTAT_DELIM_STR
"%s%s%s" QSTAT_DELIM_STR
"%s:%d" QSTAT_DELIM_STR
"%s" QSTAT_DELIM_STR
"%s" QSTAT_DELIM_STR
@ -3649,6 +3651,8 @@ static void quake_save_info (FILE *f, struct server *s) {
"%d" QSTAT_DELIM_STR
"%d\n",
games[s->type].id,
s->server_query_type != UNKNOWN_SERVER? "|" : "",
s->server_query_type != UNKNOWN_SERVER? games[s->server_query_type].id : "",
inet_ntoa (s->host->ip), s->port,
(s->name)? s->name : "",
(s->map)? s->map : "",

View File

@ -17,7 +17,7 @@
<write_config/>
<exec_client>exec_generic</exec_client>
<custom_cfgs/>
<save_info>quake_save_info</save_info>
<save_info>save_server_info</save_info>
<init_maps/>
<has_map/>
<get_mapshot/>

View File

@ -95,6 +95,7 @@ static struct server *server_new (struct host *h, unsigned short port,
server->type = type;
server->ping = -1;
server->retries = -1;
server->server_query_type = UNKNOWN_SERVER;
#ifdef USE_GEOIP
server->country_id = geoip_id_by_ip(h->ip);
@ -116,6 +117,7 @@ static struct userver *userver_new (const char *hostname, unsigned short port,
userver->hostname = g_strdup (hostname);
userver->port = port;
userver->type = type;
userver->server_query_type = UNKNOWN_SERVER;
return userver;
}
@ -473,6 +475,7 @@ struct server *userver_set_host (struct userver *us, struct host *h) {
server = server_add (h, us->port, us->type);
if (server) {
us->s = server;
us->s->server_query_type = us->server_query_type;
}
return server;

View File

@ -102,7 +102,12 @@ static void save_list (FILE *f, struct master *m) {
for (srv = m->servers; srv; srv = srv->next) {
s = (struct server *) srv->data;
fprintf (f, "%s %s:%d\n", games[s->type].id, inet_ntoa (s->host->ip), s->port);
fprintf (f, "%s%s%s %s:%d\n",
games[s->type].id,
s->server_query_type != UNKNOWN_SERVER? "|":"",
s->server_query_type != UNKNOWN_SERVER? games[s->server_query_type].id : "",
inet_ntoa (s->host->ip),
s->port);
}
fprintf (f, "\n");
@ -455,7 +460,7 @@ static void read_lists (const char *filename) {
char buf[4096];
char *ch;
struct master *m = NULL;
char *token[8];
char *token[8], *pipe;
int n;
enum server_type type;
@ -469,16 +474,18 @@ static void read_lists (const char *filename) {
while (fgets (buf, 4096, z.f)) {
n = tokenize (buf, token, 8, " \t\n\r");
if (n < 1)
if (n < 1) {
continue;
}
if (token[0][0] == '[') { // line is a master
ch = strchr (token[0] + 1, ']'); // does token 0 have a ]?
if (ch) { // it's a favorites or pre 0.9.4e lists file
*ch = '\0';
if (m && m->servers)
if (m && m->servers) {
m->servers = g_slist_reverse (m->servers);
}
m = read_list_parse_master (token[0] + 1, NULL);
}
@ -488,26 +495,42 @@ static void read_lists (const char *filename) {
*ch = '\0';
if (m && m->servers)
if (m && m->servers) {
m->servers = g_slist_reverse (m->servers);
}
m = read_list_parse_master (token[1], token[0] + 1); // master, type
}
}
}
else {
if (!m || n < 2)
if (!m || n < 2) {
continue;
}
pipe = strchr(token[0], '|');
if (pipe != NULL) {
// DESTRUCTIVE
*pipe = '\0';
}
type = id2type (token[0]);
if (type != UNKNOWN_SERVER)
if (type != UNKNOWN_SERVER) {
master_add_server (m, token[1], type);
if (pipe != NULL) {
m->server_query_type = id2type(++pipe);
}
}
}
}
if (m && m->servers)
if (m && m->servers) {
m->servers = g_slist_reverse (m->servers);
}
zstream_close (&z);
g_free (realname);
@ -807,7 +830,7 @@ static void master_options_release(QFMasterOptions* o, gboolean doit) {
g_free(o->gsmtype);
}
struct master *add_master (char *path, char *name, enum server_type type, const char* qstat_query_arg, int user, int lookup_only) {
struct master *add_master (char *path, char *name, enum server_type type, enum server_type server_query_type, const char* qstat_query_arg, int user, int lookup_only) {
char *addr = NULL;
unsigned short port = 0;
struct master *m = NULL;
@ -949,6 +972,7 @@ struct master *add_master (char *path, char *name, enum server_type type, const
return NULL;
}
m->server_query_type = server_query_type;
m->master_type = query_type;
m->options = options;
freeoptions = FALSE;
@ -1000,13 +1024,22 @@ void free_master (struct master *m) {
* DESTRUCTIVE
* @return qstat_master_option or NULL
*/
char* master_id2type(char* token, enum server_type* type) {
char* master_id2type(char* token, enum server_type* type, enum server_type* server_query_type) {
char* ret = NULL;
char* coma = strchr(token, ',');
char* comma = strchr(token, ',');
char* pipe = strchr(token, '|');
if (coma) {
*coma = '\0';
ret = ++coma;
if (comma != NULL) {
*comma = '\0';
ret = ++comma;
}
if (pipe != NULL) {
*pipe = '\0';
*server_query_type = id2type(++pipe);
}
else {
*server_query_type = UNKNOWN_SERVER;
}
*type = id2type(token);
@ -1023,6 +1056,7 @@ static void update_master_list_action (const char *action) {
char *token[4];
int n;
enum server_type type;
enum server_type server_query_type;
struct master *m;
str = strdup_strip (action);
@ -1033,16 +1067,16 @@ static void update_master_list_action (const char *action) {
n = tokenize (str, token, 4, " \t\n\r");
if (n == 4) {
char* qstat_query_arg = master_id2type (token[1], &type);
char* qstat_query_arg = master_id2type (token[1], &type, &server_query_type);
if (type != UNKNOWN_SERVER) {
if (g_ascii_strcasecmp (token[0], ACTION_ADD) == 0) {
m = add_master (token[2], token[3], type, qstat_query_arg, FALSE, FALSE);
m = add_master (token[2], token[3], type, server_query_type, qstat_query_arg, FALSE, FALSE);
if (m && source_ctree != NULL)
source_ctree_add_master (source_ctree, m);
}
else if (g_ascii_strcasecmp (token[0], ACTION_DELETE) == 0) {
m = add_master (token[2], token[3], type, qstat_query_arg, FALSE, TRUE);
m = add_master (token[2], token[3], type, server_query_type, qstat_query_arg, FALSE, TRUE);
if (m) {
if (source_ctree != NULL)
source_ctree_delete_master (source_ctree, m);
@ -1125,6 +1159,7 @@ void update_master_list_web (void) {
static void load_master_list (void) {
struct master *m;
enum server_type type;
enum server_type server_query_type;
char* qstat_query_arg = NULL;
char conf[64];
char *token[3];
@ -1151,10 +1186,11 @@ static void load_master_list (void) {
tmp = strrchr (token[0], ',');
if (tmp) {
user = (g_ascii_strcasecmp (tmp+1, "USER") == 0);
if (user)
if (user) {
*tmp = '\0';
}
}
qstat_query_arg = master_id2type (token[0], &type);
qstat_query_arg = master_id2type (token[0], &type, &server_query_type);
if (type != UNKNOWN_SERVER) {
@ -1162,7 +1198,7 @@ static void load_master_list (void) {
* and fix m->user after that.
*/
m = add_master (token[1], token[2], type, qstat_query_arg, TRUE, FALSE);
m = add_master (token[1], token[2], type, server_query_type, qstat_query_arg, TRUE, FALSE);
if (m)
m->user = user;
}
@ -1197,11 +1233,13 @@ static void save_master_list (void) {
g_snprintf (conf, 64, "master%d", n);
g_snprintf (typeid, sizeof(typeid), "%s%s%s%s",
g_snprintf (typeid, sizeof(typeid), "%s%s%s%s%s%s",
type2id (m->type),
m->_qstat_master_option?",":"",
m->_qstat_master_option?m->_qstat_master_option:"",
m->user?",USER":"");
m->server_query_type != UNKNOWN_SERVER? "|" : "",
m->server_query_type != UNKNOWN_SERVER? type2id (m->server_query_type) : "",
m->_qstat_master_option? "," : "",
m->_qstat_master_option? m->_qstat_master_option : "",
m->user? ",USER" : "");
str = master_to_url(m);
confstr = g_strjoin (" ", typeid, str, m->name, NULL);

View File

@ -26,10 +26,6 @@
#define FILENAME_LISTS "lists"
#define FILENAME_SRVINFO "srvinfo"
// #define PREFIX_MASTER "master://"
// #define PREFIX_GMASTER "gmaster://"
// #define PREFIX_URL_HTTP "http://"
#define ACTION_ADD "ADD"
#define ACTION_DELETE "DELETE"
@ -42,6 +38,7 @@ extern GSList *master_groups;
extern struct master *add_master (char *path,
char *name,
enum server_type type,
enum server_type server_query_type,
const char* qstat_query_arg,
int user,
int lookup_only);

View File

@ -144,7 +144,7 @@ static int parse_master_output (char *str, struct stat_conn *conn) {
debug (6, "parse_master_output(%s,%p)",str,conn);
n = tokenize_bychar (str, token, 8, QSTAT_DELIM);
// UGLY HACK UGLY HACK UGLY HACK UGLY HACK
// HACK: UGLY HACK UGLY HACK UGLY HACK UGLY HACK
// output from UT 2003 http server is formatted as
// ip port gamespy_port
// not the standard ip:port
@ -210,15 +210,23 @@ static int parse_master_output (char *str, struct stat_conn *conn) {
switch (n) {
// line in the form:
// <hostname>:<port>
// expected to be found in both http list and file list
case 1:
type = conn->master->type;
break;
// line in the form:
// <type>\0<hostname>:<port>
// expected to be found in qstat output
case 2:
type = id2type (token[0]);
break;
// this is not expected at all
default:
debug(3, "parse_master_output() -- bad string %s",str);
return TRUE;
}
@ -253,6 +261,9 @@ static int parse_master_output (char *str, struct stat_conn *conn) {
}
#endif
if (conn->master->server_query_type != UNKNOWN_SERVER) {
s->server_query_type = conn->master->server_query_type;
}
/*
When the "conn" is freed, it will call the function
@ -273,6 +284,11 @@ static int parse_master_output (char *str, struct stat_conn *conn) {
port += conn->master->options.portadjust;
if ((us = userver_add (addr, port, type)) != NULL) {
if (conn->master->server_query_type != UNKNOWN_SERVER) {
us->server_query_type = conn->master->server_query_type;
}
// conn->uservers = userver_list_add (conn->uservers, us);
conn->uservers = g_slist_prepend (conn->uservers, us);
userver_ref(us);
@ -413,13 +429,20 @@ static struct server *parse_server (char *token[], int n, time_t refreshed, int
struct host *h;
struct server *server;
enum server_type type;
char *addr;
char *addr, *pipe;
unsigned short port;
if (n < 3) {
return NULL;
}
pipe = strchr(token[0], '|');
if (pipe != NULL) {
// DESTRUCTIVE
*pipe = '\0';
}
type = id2type (token[0]);
if (type == UNKNOWN_SERVER) {
@ -438,7 +461,11 @@ static struct server *parse_server (char *token[], int n, time_t refreshed, int
server = server_add (h, port, type);
debug (6, "server %lx retreived", server);
if (pipe != NULL) {
server->server_query_type = id2type(++pipe);
}
debug (6, "server %lx retrieved", server);
server->flt_mask &= ~FILTER_SERVER_MASK;
@ -475,7 +502,7 @@ static struct server *parse_server (char *token[], int n, time_t refreshed, int
/*
We have a function to parse the server information,
so first we free all of the data elements of this
structure but not the structure its self. This
structure but not the structure itself. This
is because the *_analyse functions should assign values
to each of the elemets.
*/
@ -1076,7 +1103,7 @@ static struct stat_conn *stat_update_master_qstat (struct stat_job *job, struct
int argi = 0;
char buf1[64];
char* arg_type = NULL;
char buf3[64];
char buf2[64];
char buf_rawarg[] = { QSTAT_DELIM, '\0' };
struct stat_conn *conn = NULL;
char *cmd = NULL;
@ -1222,6 +1249,7 @@ static struct stat_conn *stat_update_master_qstat (struct stat_job *job, struct
startprog = 0;
file=strdup_strip(m->url + strlen(master_prefixes[MASTER_FILE]));
}
// if MASTER_HTTP
else {
cmd = strdup_strip (HTTP_HELPER);
@ -1362,11 +1390,10 @@ static struct stat_conn *stat_update_master_qstat (struct stat_job *job, struct
arg_type = g_strdup_printf ("%s,outfile", master_qstat_option(m));
}
argv[argi++] = arg_type;
argv[argi++] = buf3;
g_snprintf (buf3, 64, "%s%s:%d,-", m->master_type == MASTER_LAN?"+":"" ,inet_ntoa (m->host->ip), m->port);
argv[argi++] = buf2;
g_snprintf (buf2, 64, "%s%s:%d,-", m->master_type == MASTER_LAN?"+":"" ,inet_ntoa (m->host->ip), m->port);
argv[argi] = NULL;
@ -1400,8 +1427,7 @@ out:
return conn;
}
#define MAX_SERVERS_IN_CMDLINE 8
#define MAX_SERVERS_IN_CMDLINE 16
static struct stat_conn *stat_open_conn_qstat (struct stat_job *job) {
struct server *s = NULL;
@ -1412,6 +1438,8 @@ static struct stat_conn *stat_open_conn_qstat (struct stat_job *job) {
char *fn = NULL;
GSList *tmp;
struct stat_conn *conn;
char *qstat_query_option;
char *qstat_query_str;
char srcport[12] = {0};
if (!job->servers) {
@ -1463,12 +1491,19 @@ static struct stat_conn *stat_open_conn_qstat (struct stat_job *job) {
argv[argi++] = "-carets";
if (g_slist_length (job->servers) <= MAX_SERVERS_IN_CMDLINE) {
for (tmp = job->servers; tmp; tmp = tmp->next) {
s = (struct server *) tmp->data;
if (games[s->type].qstat_option)
argv[argi++] = games[s->type].qstat_option;
if (s->server_query_type != UNKNOWN_SERVER) {
qstat_query_option = games[s->server_query_type].qstat_option;
}
else {
qstat_query_option = games[s->type].qstat_option;
}
argv[argi++] = qstat_query_option;
argv[argi++] = &buf[bufi];
bufi += 1 + g_snprintf (&buf[bufi], sizeof (buf) - bufi, "%s:%d", inet_ntoa (s->host->ip), s->port);
@ -1491,9 +1526,17 @@ static struct stat_conn *stat_open_conn_qstat (struct stat_job *job) {
return NULL;
}
for (tmp =job-> servers; tmp; tmp = tmp->next) {
for (tmp =job->servers; tmp; tmp = tmp->next) {
s = (struct server *) tmp->data;
fprintf (f, "%s %s:%d\n", games[s->type].qstat_str, inet_ntoa (s->host->ip), s->port);
if (s->server_query_type != UNKNOWN_SERVER) {
qstat_query_str = games[s->server_query_type].qstat_str;
}
else {
qstat_query_str = games[s->type].qstat_str;
}
fprintf (f, "%s %s:%d\n", qstat_query_str, inet_ntoa (s->host->ip), s->port);
}
fclose (f);
@ -1726,6 +1769,8 @@ static void stat_name_resolved_callback (char *id, struct host *h, enum dns_stat
server_free_info (us->s);
}
us->s->server_query_type = us->server_query_type;
/*
o When the job is freed, the list will
be freed as well. This will take care of