1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
/*
* Master server communication code.
*/
#include <stdio.h>
#include <string.h>
#include "verse.h"
#include "v_util.h"
#include "vs_server.h"
#define MASTER_SERVER_PERIOD (60.0) /* Period between ANNOUNCE to master server, in seconds. */
static struct {
boolean enabled;
boolean started;
const char *master;
char desc[64];
const char *tags;
VUtilTimer timer;
} server_info;
#define LEFT(d) (sizeof server_info.desc - (d - server_info.desc) - 1)
void vs_master_set_enabled(boolean enabled)
{
server_info.enabled = enabled;
}
const char * vs_master_get_address(void)
{
return server_info.master;
}
void vs_master_set_address(const char *address)
{
server_info.master = address;
}
void vs_master_set_desc(const char *desc)
{
const char *src = desc;
char *dst = server_info.desc;
for(; *src != '\0' && LEFT(dst) > 0;)
{
if(*src == '"')
{
if(LEFT(dst) < 2)
break;
*dst++ = '\\';
}
else if(*src == '\\')
{
if(LEFT(dst) < 2)
break;
*dst++ = '\\';
}
*dst++ = *src++;
}
*dst = '\0';
}
void vs_master_set_tags(const char *tags)
{
server_info.tags = tags; /* This needs more protection, instead of relying on the master server. */
}
void vs_master_update(void)
{
if(!server_info.enabled || server_info.master == NULL)
return;
if(!server_info.started)
{
v_timer_start(&server_info.timer);
v_timer_advance(&server_info.timer, MASTER_SERVER_PERIOD);
server_info.started = TRUE;
return;
}
if(v_timer_elapsed(&server_info.timer) < MASTER_SERVER_PERIOD)
return;
verse_send_ping(server_info.master, "MS:ANNOUNCE");
v_timer_start(&server_info.timer);
/* printf("MS:ANNOUNCE sent to %s\n", server_info.master);*/
}
/* Check if a description request, of the form "A,B,C,...,D" includes the given keyword. This needs to
* do more than just a simple strstr(), since the keyword may be a prefix. Shades of OpenGL extensions.
*/
static int desc_has_keyword(const char *desc, const char *keyword)
{
const char *ptr;
if(desc == NULL || *desc == '\0') /* Quick-check for empty description. */
return 0;
if((ptr = strstr(desc, keyword)) != NULL)
{
size_t kl = strlen(keyword);
return ptr[kl] == ',' || ptr[kl] == '\0';
}
return 0;
}
static int keyword_fits(size_t used, size_t max, const char *key, const char *value)
{
size_t vsize = 0;
if(key != NULL && value != NULL)
vsize += 1 + strlen(key) + 1 + 1 + strlen(value) + 1;
return max - 1 - used >= vsize;
}
static char * append_desc(char *buf, const char *key, const char *value)
{
return buf + sprintf(buf, " %s=\"%s\"", key, value);
}
void vs_master_handle_describe(const char *address, const char *message)
{
char desc[1380] = "DESCRIPTION", *put = desc + 11;
if(desc_has_keyword(message, "DE") && server_info.desc != NULL && keyword_fits(put - desc, sizeof desc, "DE", server_info.desc))
put = append_desc(put, "DE", server_info.desc);
if(desc_has_keyword(message, "TA") && server_info.tags != NULL && keyword_fits(put - desc, sizeof desc, "TA", server_info.tags))
put = append_desc(put, "TA", server_info.tags);
verse_send_ping(address, desc);
}
|