Freeciv-3.3: /fast/freeciv/nightly/main/server/meta.c Source File

Freeciv-3.3

Loading...
Searching...
No Matches
meta.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include "fc_prehdrs.h"
19
20#include <ctype.h>
21#include <errno.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#ifdef HAVE_NETINET_IN_H
27#include <netinet/in.h>
28#endif
29#ifdef HAVE_SYS_SOCKET_H
30#include <sys/socket.h>
31#endif
32#ifdef HAVE_SYS_TYPES_H
33#include <sys/types.h>
34#endif
35#ifdef HAVE_UNISTD_H
36#include <unistd.h>
37#endif
38#ifdef HAVE_ARPA_INET_H
39#include <arpa/inet.h>
40#endif
41
42/* utility */
43#include "fcintl.h"
44#include "fcthread.h"
45#include "log.h"
46#include "mem.h"
47#include "netintf.h"
48#include "netfile.h"
49#include "support.h"
50#include "timing.h"
51
52/* common */
53#include "capstr.h"
54#include "connection.h"
55#include "dataio.h"
56#include "game.h"
57#include "map.h"
58#include "nation.h"
59#include "version.h"
60
61/* server */
62#include "console.h"
63#include "plrhand.h"
64#include "settings.h"
65#include "srv_main.h"
66
67#include "meta.h"
68
69 static bool server_is_open = FALSE;
70 static bool persistent_meta_connection = FALSE;
71 static int meta_retry_wait = 0;
72
73 static char meta_patches[256] = "";
74 static char meta_message[256] = "";
75
76#ifdef FREECIV_META_ENABLED
77static fc_thread *meta_srv_thread = NULL;
78#endif /* FREECIV_META_ENABLED */
79
80/*********************************************************************/
83 const char *default_meta_patches_string(void)
84{
85 return "none";
86}
87
88/*********************************************************************/
91 const char *default_meta_message_string(void)
92{
93#if IS_BETA_VERSION
94 return "unstable pre-" NEXT_STABLE_VERSION ": beware";
95#else /* IS_BETA_VERSION */
96#if IS_DEVEL_VERSION
97 return "development version: beware";
98#else /* IS_DEVEL_VERSION */
99 return "-";
100#endif /* IS_DEVEL_VERSION */
101#endif /* IS_BETA_VERSION */
102}
103
104/*********************************************************************/
107 const char *get_meta_patches_string(void)
108{
109 return meta_patches;
110}
111
112/*********************************************************************/
115 const char *get_meta_message_string(void)
116{
117 return meta_message;
118}
119
120#ifdef FREECIV_META_ENABLED
121/*********************************************************************/
124static const char *get_meta_type_string(void)
125{
126 if (game.server.meta_info.type[0] != '\0') {
127 return game.server.meta_info.type;
128 }
129
130 return NULL;
131}
132#endif /* FREECIV_META_ENABLED */
133
134/*********************************************************************/
137 const char *get_user_meta_message_string(void)
138{
139 if (game.server.meta_info.user_message[0] != '\0') {
140 return game.server.meta_info.user_message;
141 }
142
143 return NULL;
144}
145
146/*********************************************************************/
152 void maybe_automatic_meta_message(const char *automatic)
153{
154 const char *user_message;
155
156 user_message = get_user_meta_message_string();
157
158 if (user_message == NULL) {
159 /* No user message */
160 if (automatic != NULL) {
161 set_meta_message_string(automatic);
162 }
163 return;
164 }
165
166 set_meta_message_string(user_message);
167}
168
169/*********************************************************************/
172 void set_meta_patches_string(const char *string)
173{
174 sz_strlcpy(meta_patches, string);
175}
176
177/*********************************************************************/
180 void set_meta_message_string(const char *string)
181{
182 sz_strlcpy(meta_message, string);
183}
184
185/*********************************************************************/
188 void set_user_meta_message_string(const char *string)
189{
190 if (string != NULL && string[0] != '\0') {
191 sz_strlcpy(game.server.meta_info.user_message, string);
192 set_meta_message_string(string);
193 } else {
194 /* Remove user meta message. We will use automatic messages instead */
195 game.server.meta_info.user_message[0] = '\0';
196 set_meta_message_string(default_meta_message_string());
197 }
198}
199
200/*********************************************************************/
203 char *meta_addr_port(void)
204{
205 return srvarg.metaserver_addr;
206}
207
208#ifdef FREECIV_META_ENABLED
209/*********************************************************************/
212static void metaserver_failed(void)
213{
214 if (!persistent_meta_connection) {
215 con_puts(C_METAERROR, _("Not reporting to the metaserver in this game."));
216 con_flush();
217
218 server_close_meta();
219 } else {
220 con_puts(C_METAERROR, _("Metaserver connection currently failing."));
221 meta_retry_wait = 1;
222 }
223}
224
225/*********************************************************************/
228static inline bool meta_insert_setting(struct netfile_post *post,
229 const char *set_name)
230{
231 const struct setting *pset = setting_by_name(set_name);
232 char buf[256];
233
234 fc_assert_ret_val_msg(NULL != pset, FALSE,
235 "Setting \"%s\" not found!", set_name);
236 netfile_add_form_str(post, "vn[]", setting_name(pset));
237 netfile_add_form_str(post, "vv[]",
238 setting_value_name(pset, FALSE, buf, sizeof(buf)));
239 return TRUE;
240}
241
242/*********************************************************************/
245static void send_metaserver_post(void *arg)
246{
247 struct netfile_post *post = (struct netfile_post *) arg;
248 char *addr;
249
250 if (srvarg.bind_meta_addr != NULL) {
251 addr = srvarg.bind_meta_addr;
252 } else {
253 addr = srvarg.bind_addr;
254 }
255
256 if (!netfile_send_post(srvarg.metaserver_addr, post, NULL, NULL, addr)) {
257 con_puts(C_METAERROR, _("Error connecting to metaserver"));
258 metaserver_failed();
259 }
260
261 netfile_close_post(post);
262}
263
264/*********************************************************************/
267static bool send_to_metaserver(enum meta_flag flag)
268{
269 int players = 0;
270 int humans = 0;
271 char host[512];
272 char state[20];
273 char rs[256];
274 struct netfile_post *post;
275
276 switch (server_state()) {
277 case S_S_INITIAL:
278 sz_strlcpy(state, "Pregame");
279 break;
280 case S_S_RUNNING:
281 sz_strlcpy(state, "Running");
282 break;
283 case S_S_OVER:
284 sz_strlcpy(state, "Game Ended");
285 break;
286 }
287
288 /* Get hostname */
289 if (srvarg.identity_name[0] != '\0') {
290 sz_strlcpy(host, srvarg.identity_name);
291 } else if (fc_gethostname(host, sizeof(host)) != 0) {
292 sz_strlcpy(host, "unknown");
293 }
294
295 if (game.control.version[0] != '\0') {
296 fc_snprintf(rs, sizeof(rs), "%s %s", game.control.name, game.control.version);
297 } else {
298 sz_strlcpy(rs, game.control.name);
299 }
300
301 /* Freed in metaserver thread function send_metaserver_post() */
302 post = netfile_start_post();
303
304 netfile_add_form_str(post, "host", host);
305 netfile_add_form_int(post, "port", srvarg.port);
306 netfile_add_form_str(post, "state", state);
307 netfile_add_form_str(post, "ruleset", rs);
308
309 if (flag == META_GOODBYE) {
310 netfile_add_form_int(post, "bye", 1);
311 } else {
312 const char *srvtype = get_meta_type_string();
313
314 if (srvtype != NULL) {
315 netfile_add_form_str(post, "type", srvtype);
316 }
317 netfile_add_form_str(post, "version", VERSION_STRING);
318 netfile_add_form_str(post, "patches",
319 get_meta_patches_string());
320 netfile_add_form_str(post, "capability", our_capability);
321
322 netfile_add_form_str(post, "serverid", srvarg.serverid);
323 netfile_add_form_str(post, "message",
324 get_meta_message_string());
325
326 /* NOTE: Send info for ALL players or none at all. */
327 if (normal_player_count() == 0) {
328 netfile_add_form_int(post, "dropplrs", 1);
329 } else {
330 players = 0; /* Counter for players_available */
331 humans = 0;
332
333 players_iterate(plr) {
334 bool is_player_available = TRUE;
335 char type[15];
336 struct connection *pconn = conn_by_user(plr->username);
337
338 if (!plr->is_alive) {
339 sz_strlcpy(type, "Dead");
340 } else if (is_barbarian(plr)) {
341 sz_strlcpy(type, "Barbarian");
342 } else if (is_ai(plr)) {
343 sz_strlcpy(type, "A.I.");
344 } else if (is_human(plr)) {
345 sz_strlcpy(type, "Human");
346 } else {
347 sz_strlcpy(type, "-");
348 }
349
350 netfile_add_form_str(post, "plu[]", plr->username);
351 netfile_add_form_str(post, "plt[]", type);
352 netfile_add_form_str(post, "pll[]", player_name(plr));
353 netfile_add_form_str(post, "pln[]",
354 plr->nation != NO_NATION_SELECTED
355 ? nation_plural_for_player(plr)
356 : "none");
357 netfile_add_form_str(post, "plf[]",
358 plr->nation != NO_NATION_SELECTED
359 ? nation_of_player(plr)->flag_graphic_str
360 : "none");
361 netfile_add_form_str(post, "plh[]",
362 pconn ? pconn->addr : "");
363
364 /* Is this player available to take?
365 * TODO: There's some duplication here with
366 * stdinhand.c:is_allowed_to_take() */
367 if (is_barbarian(plr) && !strchr(game.server.allow_take, 'b')) {
368 is_player_available = FALSE;
369 } else if (!plr->is_alive && !strchr(game.server.allow_take, 'd')) {
370 is_player_available = FALSE;
371 } else if (is_ai(plr)
372 && !strchr(game.server.allow_take,
373 (game.info.is_new_game ? 'A' : 'a'))) {
374 is_player_available = FALSE;
375 } else if (is_human(plr)
376 && !strchr(game.server.allow_take,
377 (game.info.is_new_game ? 'H' : 'h'))) {
378 is_player_available = FALSE;
379 }
380
381 if (pconn) {
382 is_player_available = FALSE;
383 }
384
385 if (is_player_available) {
386 players++;
387 }
388
389 if (is_human(plr) && plr->is_alive) {
390 humans++;
391 }
392 } players_iterate_end;
393
394 /* Send the number of available players. */
395 netfile_add_form_int(post, "available", players);
396 netfile_add_form_int(post, "humans", humans);
397 }
398
399 /* Send some variables: should be listed in inverted order? */
400 {
401 static const char *settings[] = {
402 "timeout", "endturn", "minplayers", "maxplayers",
403 "aifill", "allowtake", "generator"
404 };
405 int i;
406
407 for (i = 0; i < ARRAY_SIZE(settings); i++) {
408 meta_insert_setting(post, settings[i]);
409 }
410
411 /* HACK: Send the most determinant setting for the map size. */
412 switch (wld.map.server.mapsize) {
413 case MAPSIZE_FULLSIZE:
414 meta_insert_setting(post, "size");
415 break;
416 case MAPSIZE_PLAYER:
417 meta_insert_setting(post, "tilesperplayer");
418 break;
419 case MAPSIZE_XYSIZE:
420 meta_insert_setting(post, "xsize");
421 meta_insert_setting(post, "ysize");
422 break;
423 }
424 }
425
426 /* Turn and year. */
427 netfile_add_form_str(post, "vn[]", "turn");
428 netfile_add_form_int(post, "vv[]", game.info.turn);
429 netfile_add_form_str(post, "vn[]", "year");
430
431 if (server_state() != S_S_INITIAL) {
432 netfile_add_form_int(post, "vv[]", game.info.year);
433 } else {
434 netfile_add_form_str(post, "vv[]", "Calendar not set up");
435 }
436 }
437
438 if (meta_srv_thread != NULL) {
439 /* Previously started thread */
440 fc_thread_wait(meta_srv_thread);
441 } else {
442 meta_srv_thread = fc_malloc(sizeof(meta_srv_thread));
443 }
444
445 /* Send POST in new thread */
446 fc_thread_start(meta_srv_thread, &send_metaserver_post, post);
447
448 return TRUE;
449}
450#endif /* FREECIV_META_ENABLED */
451
452/*********************************************************************/
455 void server_close_meta(void)
456{
457 server_is_open = FALSE;
458 persistent_meta_connection = FALSE;
459}
460
461/*********************************************************************/
464 bool server_open_meta(bool persistent)
465{
466 if (meta_patches[0] == '\0') {
467 set_meta_patches_string(default_meta_patches_string());
468 }
469 if (meta_message[0] == '\0') {
470 set_meta_message_string(default_meta_message_string());
471 }
472
473 server_is_open = TRUE;
474 persistent_meta_connection = persistent;
475 meta_retry_wait = 0;
476
477 return TRUE;
478}
479
480/*********************************************************************/
483 bool is_metaserver_open(void)
484{
485 return server_is_open;
486}
487
488/*********************************************************************/
491 bool send_server_info_to_metaserver(enum meta_flag flag)
492{
493#ifndef FREECIV_META_ENABLED
494
495 return FALSE;
496
497#else /* FREECIV_META_ENABLED */
498
499 static struct timer *last_send_timer = NULL;
500 static bool want_update;
501 int since_previous;
502
503 if (!server_is_open) {
504 return FALSE;
505 }
506
507 /* Persistent connection temporary failures handling */
508 if (meta_retry_wait > 0) {
509 if (meta_retry_wait++ > 5) {
510 meta_retry_wait = 0;
511 } else {
512 return FALSE;
513 }
514 }
515
516 /* If we're bidding farewell, ignore all timers */
517 if (flag == META_GOODBYE) {
518 if (last_send_timer) {
519 timer_destroy(last_send_timer);
520 last_send_timer = NULL;
521 }
522 send_to_metaserver(flag);
523
524 /* Wait metaserver thread to finish */
525 fc_thread_wait(meta_srv_thread);
526 free(meta_srv_thread);
527 meta_srv_thread = NULL;
528
529 return TRUE;
530 }
531
532 if (last_send_timer != NULL) {
533 since_previous = timer_read_seconds(last_send_timer);
534
535 /* Don't allow the user to spam the metaserver with updates */
536 if (since_previous < METASERVER_MIN_UPDATE_INTERVAL) {
537 if (flag == META_INFO) {
538 want_update = TRUE; /* We couldn't update now, but update a.s.a.p. */
539 }
540
541 return FALSE;
542 }
543 } else {
544 since_previous = MAX(METASERVER_REFRESH_INTERVAL + 1,
545 METASERVER_MIN_UPDATE_INTERVAL + 1);
546 }
547
548 /* If we're asking for a refresh, only do so if
549 * we've exceeded the refresh interval */
550 if ((flag == META_REFRESH) && !want_update
551 && since_previous < METASERVER_REFRESH_INTERVAL) {
552 return FALSE;
553 }
554
555 /* Start a new timer if we haven't already */
556 if (last_send_timer == NULL) {
557 last_send_timer = timer_new(TIMER_USER, TIMER_ACTIVE, "meta");
558 }
559
560 timer_clear(last_send_timer);
561 timer_start(last_send_timer);
562 want_update = FALSE;
563
564 return send_to_metaserver(flag);
565#endif /* FREECIV_META_ENABLED */
566}
our_capability
const char *const our_capability
Definition capstr.c:32
capstr.h
incite_cost
char * incite_cost
Definition comments.c:74
conn_by_user
struct connection * conn_by_user(const char *user_name)
Definition connection.c:377
connection.h
con_flush
void con_flush(void)
Definition console.c:243
con_puts
void con_puts(enum rfc_status rfc_status, const char *str)
Definition console.c:226
console.h
C_METAERROR
@ C_METAERROR
Definition console.h:46
dataio.h
fc_prehdrs.h
fcintl.h
_
#define _(String)
Definition fcintl.h:67
fcthread.h
fc_thread_start
int fc_thread_start(fc_thread *thread, void(*function)(void *arg), void *arg)
fc_thread_wait
void fc_thread_wait(fc_thread *thread)
game
struct civ_game game
Definition game.c:62
wld
struct world wld
Definition game.c:63
game.h
persistent
static GtkWidget * persistent
Definition rallypointdlg.c:40
type
GType type
Definition repodlgs.c:1313
log.h
fc_assert_ret_val_msg
#define fc_assert_ret_val_msg(condition, val, message,...)
Definition log.h:208
map.h
MAPSIZE_FULLSIZE
@ MAPSIZE_FULLSIZE
Definition map_types.h:39
MAPSIZE_PLAYER
@ MAPSIZE_PLAYER
Definition map_types.h:40
MAPSIZE_XYSIZE
@ MAPSIZE_XYSIZE
Definition map_types.h:43
mem.h
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
maybe_automatic_meta_message
void maybe_automatic_meta_message(const char *automatic)
Definition meta.c:152
set_meta_patches_string
void set_meta_patches_string(const char *string)
Definition meta.c:172
get_user_meta_message_string
const char * get_user_meta_message_string(void)
Definition meta.c:137
is_metaserver_open
bool is_metaserver_open(void)
Definition meta.c:483
persistent_meta_connection
static bool persistent_meta_connection
Definition meta.c:70
meta_addr_port
char * meta_addr_port(void)
Definition meta.c:203
set_meta_message_string
void set_meta_message_string(const char *string)
Definition meta.c:180
meta_message
static char meta_message[256]
Definition meta.c:74
default_meta_message_string
const char * default_meta_message_string(void)
Definition meta.c:91
server_close_meta
void server_close_meta(void)
Definition meta.c:455
default_meta_patches_string
const char * default_meta_patches_string(void)
Definition meta.c:83
get_meta_message_string
const char * get_meta_message_string(void)
Definition meta.c:115
send_server_info_to_metaserver
bool send_server_info_to_metaserver(enum meta_flag flag)
Definition meta.c:491
meta_retry_wait
static int meta_retry_wait
Definition meta.c:71
server_is_open
static bool server_is_open
Definition meta.c:69
server_open_meta
bool server_open_meta(bool persistent)
Definition meta.c:464
get_meta_patches_string
const char * get_meta_patches_string(void)
Definition meta.c:107
set_user_meta_message_string
void set_user_meta_message_string(const char *string)
Definition meta.c:188
meta_patches
static char meta_patches[256]
Definition meta.c:73
meta.h
METASERVER_REFRESH_INTERVAL
#define METASERVER_REFRESH_INTERVAL
Definition meta.h:22
METASERVER_MIN_UPDATE_INTERVAL
#define METASERVER_MIN_UPDATE_INTERVAL
Definition meta.h:23
meta_flag
meta_flag
Definition meta.h:25
META_GOODBYE
@ META_GOODBYE
Definition meta.h:28
META_INFO
@ META_INFO
Definition meta.h:26
META_REFRESH
@ META_REFRESH
Definition meta.h:27
nation_of_player
struct nation_type * nation_of_player(const struct player *pplayer)
Definition nation.c:444
nation_plural_for_player
const char * nation_plural_for_player(const struct player *pplayer)
Definition nation.c:178
nation.h
NO_NATION_SELECTED
#define NO_NATION_SELECTED
Definition nation.h:30
netfile_close_post
void netfile_close_post(struct netfile_post *post)
Definition netfile.c:244
netfile_start_post
struct netfile_post * netfile_start_post(void)
Definition netfile.c:197
netfile_send_post
bool netfile_send_post(const char *URL, struct netfile_post *post, FILE *reply_fp, struct netfile_write_cb_data *mem_data, const char *addr)
Definition netfile.c:268
netfile_add_form_int
void netfile_add_form_int(struct netfile_post *post, const char *name, const int val)
Definition netfile.c:232
netfile_add_form_str
void netfile_add_form_str(struct netfile_post *post, const char *name, const char *val)
Definition netfile.c:211
netfile.h
netintf.h
player_name
const char * player_name(const struct player *pplayer)
Definition player.c:895
players_iterate_end
#define players_iterate_end
Definition player.h:539
players_iterate
#define players_iterate(_pplayer)
Definition player.h:534
is_barbarian
static bool is_barbarian(const struct player *pplayer)
Definition player.h:491
is_ai
#define is_ai(plr)
Definition player.h:232
is_human
#define is_human(plr)
Definition player.h:231
normal_player_count
int normal_player_count(void)
Definition plrhand.c:3208
plrhand.h
setting_by_name
struct setting * setting_by_name(const char *name)
Definition settings.c:3302
setting_value_name
const char * setting_value_name(const struct setting *pset, bool pretty, char *buf, size_t buf_len)
Definition settings.c:4260
settings
static struct setting settings[]
Definition settings.c:1474
setting_name
const char * setting_name(const struct setting *pset)
Definition settings.c:3326
settings.h
ARRAY_SIZE
#define ARRAY_SIZE(x)
Definition shared.h:85
MAX
#define MAX(x, y)
Definition shared.h:54
srvarg
struct server_arguments srvarg
Definition srv_main.c:180
server_state
enum server_states server_state(void)
Definition srv_main.c:337
srv_main.h
civ_game::type
char type[20]
Definition game.h:267
civ_game::control
struct packet_ruleset_control control
Definition game.h:83
civ_game::info
struct packet_game_info info
Definition game.h:89
civ_game::user_message
char user_message[256]
Definition game.h:266
civ_game::server
struct civ_game::@31::@35 server
civ_game::meta_info
struct civ_game::@31::@35::@38 meta_info
civ_game::allow_take
char allow_take[MAX_LEN_ALLOW_TAKE]
Definition game.h:241
civ_map::mapsize
enum mapsize_type mapsize
Definition map_types.h:89
civ_map::server
struct civ_map::@42::@44 server
connection
Definition connection.h:136
netfile_post
Definition netfile.c:39
packet_game_info::is_new_game
bool is_new_game
Definition packets_gen.h:192
packet_game_info::turn
int turn
Definition packets_gen.h:247
packet_game_info::year
int year
Definition packets_gen.h:249
packet_ruleset_control::version
char version[MAX_LEN_NAME]
Definition packets_gen.h:1485
packet_ruleset_control::name
char name[MAX_LEN_NAME]
Definition packets_gen.h:1484
server_arguments::bind_addr
char * bind_addr
Definition srv_main.h:34
server_arguments::metaserver_addr
char metaserver_addr[256]
Definition srv_main.h:29
server_arguments::bind_meta_addr
char * bind_meta_addr
Definition srv_main.h:38
server_arguments::serverid
char serverid[256]
Definition srv_main.h:49
server_arguments::identity_name
char identity_name[256]
Definition srv_main.h:31
server_arguments::port
int port
Definition srv_main.h:36
setting
Definition settings.c:92
timer
Definition timing.c:81
world::map
struct civ_map map
Definition world_object.h:38
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
fc_gethostname
int fc_gethostname(char *buf, size_t len)
Definition support.c:1007
support.h
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:189
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
timer_clear
void timer_clear(struct timer *t)
Definition timing.c:252
timer_destroy
void timer_destroy(struct timer *t)
Definition timing.c:208
timer_start
void timer_start(struct timer *t)
Definition timing.c:264
timer_new
struct timer * timer_new(enum timer_timetype type, enum timer_use use, const char *name)
Definition timing.c:160
timer_read_seconds
double timer_read_seconds(struct timer *t)
Definition timing.c:384
timing.h
TIMER_ACTIVE
@ TIMER_ACTIVE
Definition timing.h:46
TIMER_USER
@ TIMER_USER
Definition timing.h:42
version.h