DEADSOFTWARE

Net: Start ebin master upgrade
[d2df-sdl.git] / src / mastersrv / master.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <enet/enet.h>
5 #include <enet/types.h>
7 #define MS_VERSION "0.2"
8 #define MS_MAXSRVS 128
9 #define MS_TIMEOUT 100
11 #define NET_CHANS 2
12 #define NET_CH_MAIN 0
13 #define NET_CH_UPD 1
14 #define NET_MAXCLIENTS 64
16 #define NET_BUFSIZE 65536
18 #define NET_MSG_ADD 200
19 #define NET_MSG_RM 201
20 #define NET_MSG_LIST 202
22 #define LC_MS_INIT "D2DF master server starting on port %d...\n"
23 #define LC_MS_ADD "\nAdded server in slot #%d:\n%s:%d\n%s\n%s (%d)\n%d/%d plrs\nproto: %d pw?: %d\n"
24 #define LC_MS_UPD "\nUpdated server #%d (%s:%d):\n%s\n%s (%d)\n%d/%d plrs\nproto: %d pw?: %d\n"
25 #define LC_MS_RM "\nRemoved server #%d (%s:%d) by request.\n"
26 #define LC_MS_TIME "\nServer #%d (%s:%d) timed out.\n"
27 #define LC_MS_LIST "\nSent server list to %x:%u (ver. %s).\n"
28 #define LC_MS_DIE "\nD2DF master server shutting down...\n"
29 #define LC_MS_CONN "\nIncoming connection from %x:%u...\n"
32 struct ms_server_s {
33 enet_uint8 used;
34 char s_ip[17];
35 char s_name[256];
36 char s_map[256];
37 enet_uint8 s_pw;
38 enet_uint8 s_plrs;
39 enet_uint8 s_maxplrs;
40 enet_uint8 s_mode;
41 enet_uint8 s_protocol;
42 enet_uint16 s_port;
43 enet_uint32 ttl;
44 };
46 typedef struct ms_server_s ms_server;
48 const char ms_game_ver[] = "0.63";
49 int ms_port = 25660;
50 int ms_timeout = 100000;
52 size_t b_read = 0;
53 size_t b_write = 0;
55 enet_uint8 b_send[NET_BUFSIZE];
57 ENetHost *ms_host = NULL;
58 ENetPeer *ms_peers[NET_MAXCLIENTS];
59 ms_server ms_srv[MS_MAXSRVS];
60 enet_uint8 ms_count = 0;
62 // fake servers to show on old versions of the game
63 static const ms_server ms_fake_srv[] = {
64 {
65 .used = 1,
66 .s_ip = "0.0.0.0",
67 .s_name = "! \xc2\xc0\xd8\xc0 \xca\xce\xcf\xc8\xdf \xc8\xc3\xd0\xdb "
68 "\xd3\xd1\xd2\xc0\xd0\xc5\xcb\xc0! "
69 "\xd1\xca\xc0\xd7\xc0\xc9\xd2\xc5 \xcd\xce\xc2\xd3\xde C "
70 "doom2d.org !",
71 .s_map = "! Your game is outdated. "
72 "Get latest version at doom2d.org !",
73 .s_protocol = 255,
74 },
75 {
76 .used = 1,
77 .s_ip = "0.0.0.0",
78 .s_name = "! \xcf\xd0\xce\xc1\xd0\xce\xd1\xdcTE \xcf\xce\xd0\xd2\xdb "
79 "25666 \xc8 57133 HA CEPBEPE \xcf\xc5\xd0\xc5\xc4 \xc8\xc3\xd0\xce\xc9 !",
80 .s_map = "! Forward ports 25666 and 57133 before hosting !",
81 .s_protocol = 255,
82 },
83 };
85 #define MS_FAKESRVS (sizeof(ms_fake_srv) / sizeof(ms_fake_srv[0]))
87 void i_usage () {
88 printf("Usage: d2df_master -p port_number [-t timeout_seconds]\n");
89 fflush(stdout);
90 }
93 void i_version () {
94 printf("Doom 2D Forever master server v%s\n", MS_VERSION);
95 fflush(stdout);
96 }
99 void d_error (const char *msg, int fatal) {
100 if (fatal) {
101 fprintf(stderr, "FATAL ERROR: %s\n", msg);
102 exit(EXIT_FAILURE);
103 } else {
104 fprintf(stderr, "ERROR: %s\n", msg);
109 void d_getargs (int argc, char *argv[]) {
110 if (argc < 2) {
111 i_usage();
112 exit(0);
113 return;
116 for (int i = 1; i < argc; ++i) {
117 if (!strcmp(argv[i], "-v")) {
118 i_version();
119 exit(0);
120 return;
121 } else if (!strcmp(argv[i], "-p")) {
122 if (i + 1 >= argc) {
123 d_error("Specify a port value!", 1);
124 return;
125 } else {
126 ms_port = atoi(argv[++i]);
128 } else if (!strcmp(argv[i], "-t") & (i + 1 < argc)) {
129 ms_timeout = atoi(argv[++i]) * 1000;
135 enet_uint8 b_read_uint8 (enet_uint8 buf[], size_t *pos) {
136 return buf[(*pos)++];
140 enet_uint16 b_read_uint16 (enet_uint8 buf[], size_t *pos) {
141 enet_uint16 ret = 0;
143 ret = *(enet_uint16*)(buf + *pos);
144 *pos += sizeof(enet_uint16);
146 return ret;
150 char* b_read_dstring (enet_uint8 buf[], size_t *pos) {
151 char *ret = NULL;
153 size_t len = b_read_uint8(buf, pos);
155 ret = malloc(len + 1);
157 memmove(ret, (char*)(buf + *pos), len);
158 ret[len] = '\0';
159 *pos += len;
161 return ret;
165 void b_write_uint8 (enet_uint8 buf[], size_t *pos, enet_uint8 val) {
166 buf[(*pos)++] = val;
170 void b_write_uint16 (enet_uint8 buf[], size_t *pos, enet_uint16 val) {
171 *(enet_uint16*)(buf + *pos) = val;
172 *pos += sizeof(enet_uint16);
176 void b_write_dstring (enet_uint8 buf[], size_t *pos, const char* val) {
177 enet_uint8 len = strlen(val);
178 b_write_uint8(buf, pos, len);
180 memmove((char*)(buf + *pos), val, len);
181 *pos += len;
185 void b_write_server (enet_uint8 buf[], size_t *pos, ms_server s) {
186 b_write_dstring(b_send, pos, s.s_ip);
187 b_write_uint16 (b_send, pos, s.s_port);
188 b_write_dstring(b_send, pos, s.s_name);
189 b_write_dstring(b_send, pos, s.s_map);
190 b_write_uint8 (b_send, pos, s.s_mode);
191 b_write_uint8 (b_send, pos, s.s_plrs);
192 b_write_uint8 (b_send, pos, s.s_maxplrs);
193 b_write_uint8 (b_send, pos, s.s_protocol);
194 b_write_uint8 (b_send, pos, s.s_pw);
198 int main (int argc, char *argv[]) {
199 d_getargs(argc, argv);
201 if (enet_initialize()) {
202 d_error("Could not init ENet!", 1);
203 return EXIT_FAILURE;
206 printf(LC_MS_INIT, ms_port);
208 for (int i = 0; i < NET_MAXCLIENTS; ++i) ms_peers[i] = NULL;
210 for (int i = 0; i < MS_MAXSRVS; ++i) {
211 ms_srv[i].used = 0;
212 ms_srv[i].s_ip[0] = '\0';
213 ms_srv[i].s_name[0] = '\0';
214 ms_srv[i].s_map[0] = '\0';
215 ms_srv[i].ttl = 0;
218 ENetAddress addr;
219 addr.host = ENET_HOST_ANY;
220 addr.port = ms_port;
222 ms_host = enet_host_create(&addr, NET_MAXCLIENTS, NET_CHANS, 0, 0);
223 if (!ms_host) {
224 d_error("Could not create host on specified port!", 1);
225 return EXIT_FAILURE;
228 atexit(enet_deinitialize);
230 ENetEvent event;
231 int shutdown = 0;
232 enet_uint8 msg = 255;
234 char ip[17];
235 enet_uint16 port = 0;
237 char *name = NULL;
238 char *map = NULL;
239 char *clientver = NULL;
240 enet_uint8 gm = 0;
241 enet_uint16 pl = 0;
242 enet_uint16 mpl = 0;
244 enet_uint8 proto = 0;
245 enet_uint8 pw = 0;
246 while (!shutdown) {
247 while (enet_host_service(ms_host, &event, 1) > 0) {
248 switch (event.type) {
249 case ENET_EVENT_TYPE_CONNECT:
250 printf(LC_MS_CONN, event.peer->address.host, event.peer->address.port);
251 break;
252 case ENET_EVENT_TYPE_RECEIVE:
253 if (!event.peer) continue;
254 b_read = 0;
255 msg = b_read_uint8(event.packet->data, &b_read);
257 switch (msg) {
258 case NET_MSG_ADD:
259 if (!event.peer) continue;
261 enet_address_get_host_ip(&(event.peer->address), ip, 17);
262 port = b_read_uint16(event.packet->data, &b_read);
264 name = b_read_dstring(event.packet->data, &b_read);
265 map = b_read_dstring(event.packet->data, &b_read);
266 gm = b_read_uint8(event.packet->data, &b_read);
268 pl = b_read_uint8(event.packet->data, &b_read);
269 mpl = b_read_uint8(event.packet->data, &b_read);
271 proto = b_read_uint8(event.packet->data, &b_read);
272 pw = b_read_uint8(event.packet->data, &b_read);
274 for (int i = 0; i < MS_MAXSRVS; ++i) {
275 if (ms_srv[i].used) {
276 if ((strncmp(ip, ms_srv[i].s_ip, 16) == 0) && (ms_srv[i].s_port == port)) {
277 strncpy(ms_srv[i].s_map, map, sizeof(ms_srv[i].s_map));
278 strncpy(ms_srv[i].s_name, name, sizeof(ms_srv[i].s_name));
279 ms_srv[i].s_plrs = pl;
280 ms_srv[i].s_maxplrs = mpl;
281 ms_srv[i].s_pw = pw;
282 ms_srv[i].s_mode = gm;
284 ms_srv[i].ttl = ms_timeout;
286 printf(LC_MS_UPD, i, ip, port, name, map, gm, pl, mpl, proto, pw);
287 break;
289 } else {
290 strncpy(ms_srv[i].s_ip, ip, sizeof(ms_srv[i].s_ip));
291 strncpy(ms_srv[i].s_map, map, sizeof(ms_srv[i].s_map));
292 strncpy(ms_srv[i].s_name, name, sizeof(ms_srv[i].s_name));
293 ms_srv[i].s_port = port;
294 ms_srv[i].s_plrs = pl;
295 ms_srv[i].s_maxplrs = mpl;
296 ms_srv[i].s_pw = pw;
297 ms_srv[i].s_mode = gm;
298 ms_srv[i].s_protocol = proto;
299 ms_srv[i].ttl = ms_timeout;
301 ms_srv[i].used = 1;
303 printf(LC_MS_ADD, i, ip, port, name, map, gm, pl, mpl, proto, pw);
305 ++ms_count;
306 break;
309 free(name);
310 free(map);
311 break;
312 case NET_MSG_RM:
313 enet_address_get_host_ip(&(event.peer->address), ip, 17);
314 port = b_read_uint16(event.packet->data, &b_read);
315 for (int i = 0; i < MS_MAXSRVS; ++i) {
316 if (ms_srv[i].used) {
317 if ((strncmp(ip, ms_srv[i].s_ip, 16) == 0) && (ms_srv[i].s_port == port)) {
318 ms_srv[i].used = 0;
319 printf(LC_MS_RM, i, ip, port);
320 --ms_count;
324 break;
325 case NET_MSG_LIST:
326 if (!event.peer) continue;
328 b_write = 0;
329 b_write_uint8(b_send, &b_write, NET_MSG_LIST);
331 if (event.packet->dataLength > 2) {
332 // holy shit a fresh client
333 clientver = b_read_dstring(event.packet->data, &b_read);
334 b_write_uint8(b_send, &b_write, ms_count);
335 } else {
336 // old client, feed them bullshit first
337 b_write_uint8(b_send, &b_write, ms_count + 2);
338 for (int i = 0; i < MS_FAKESRVS; ++i)
339 b_write_server(b_send, &b_write, ms_fake_srv[i]);
342 for (int i = 0; i < MS_MAXSRVS; ++i) {
343 if (ms_srv[i].used) b_write_server(b_send, &b_write, ms_srv[i]);
346 if (clientver) {
347 // TODO: check if this client is outdated (?) and send back new verstring
348 // for now just write the same shit back
349 b_write_dstring(b_send, &b_write, clientver);
352 ENetPacket *p = enet_packet_create(b_send, b_write, ENET_PACKET_FLAG_RELIABLE);
353 enet_peer_send(event.peer, NET_CH_MAIN, p);
354 enet_host_flush(ms_host);
356 printf(LC_MS_LIST, event.peer->address.host, event.peer->address.port, clientver ? clientver : "<old>");
357 free(clientver);
358 clientver = NULL;
359 break;
362 enet_packet_destroy(event.packet);
363 break;
365 default:
366 break;
370 for (int i = 0; i < MS_MAXSRVS; ++i) {
371 if (ms_srv[i].used) {
372 if (--(ms_srv[i].ttl) == 0) {
373 ms_srv[i].used = 0;
374 printf(LC_MS_TIME, i, ms_srv[i].s_ip, ms_srv[i].s_port);
375 --ms_count;
381 printf(LC_MS_DIE);
383 return EXIT_SUCCESS;