Freeciv-3.1: /fast/freeciv/nightly/S3_1/server/meta.c Source File

Freeciv-3.1

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 "version.h"
59
60/* server */
61#include "console.h"
62#include "plrhand.h"
63#include "settings.h"
64#include "srv_main.h"
65
66#include "meta.h"
67
68 static bool server_is_open = FALSE;
69 static bool persistent_meta_connection = FALSE;
70 static int meta_retry_wait = 0;
71
72 static char meta_patches[256] = "";
73 static char meta_message[256] = "";
74
75#ifdef FREECIV_META_ENABLED
76static fc_thread *meta_srv_thread = NULL;
77#endif /* FREECIV_META_ENABLED */
78
79/*********************************************************************/
82 const char *default_meta_patches_string(void)
83{
84 return "none";
85}
86
87/*********************************************************************/
90 const char *default_meta_message_string(void)
91{
92#if IS_BETA_VERSION
93 return "unstable pre-" NEXT_STABLE_VERSION ": beware";
94#else /* IS_BETA_VERSION */
95#if IS_DEVEL_VERSION
96 return "development version: beware";
97#else /* IS_DEVEL_VERSION */
98 return "-";
99#endif /* IS_DEVEL_VERSION */
100#endif /* IS_BETA_VERSION */
101}
102
103/*********************************************************************/
106 const char *get_meta_patches_string(void)
107{
108 return meta_patches;
109}
110
111/*********************************************************************/
114 const char *get_meta_message_string(void)
115{
116 return meta_message;
117}
118
119#ifdef FREECIV_META_ENABLED
120/*********************************************************************/
123static const char *get_meta_type_string(void)
124{
125 if (game.server.meta_info.type[0] != '\0') {
126 return game.server.meta_info.type;
127 }
128
129 return NULL;
130}
131#endif /* FREECIV_META_ENABLED */
132
133/*********************************************************************/
136 const char *get_user_meta_message_string(void)
137{
138 if (game.server.meta_info.user_message[0] != '\0') {
139 return game.server.meta_info.user_message;
140 }
141
142 return NULL;
143}
144
145/*********************************************************************/
151 void maybe_automatic_meta_message(const char *automatic)
152{
153 const char *user_message;
154
155 user_message = get_user_meta_message_string();
156
157 if (user_message == NULL) {
158 /* No user message */
159 if (automatic != NULL) {
160 set_meta_message_string(automatic);
161 }
162 return;
163 }
164
165 set_meta_message_string(user_message);
166}
167
168/*********************************************************************/
171 void set_meta_patches_string(const char *string)
172{
173 sz_strlcpy(meta_patches, string);
174}
175
176/*********************************************************************/
179 void set_meta_message_string(const char *string)
180{
181 sz_strlcpy(meta_message, string);
182}
183
184/*********************************************************************/
187 void set_user_meta_message_string(const char *string)
188{
189 if (string != NULL && string[0] != '\0') {
190 sz_strlcpy(game.server.meta_info.user_message, string);
191 set_meta_message_string(string);
192 } else {
193 /* Remove user meta message. We will use automatic messages instead */
194 game.server.meta_info.user_message[0] = '\0';
195 set_meta_message_string(default_meta_message_string());
196 }
197}
198
199/*********************************************************************/
202 char *meta_addr_port(void)
203{
204 return srvarg.metaserver_addr;
205}
206
207#ifdef FREECIV_META_ENABLED
208/*********************************************************************/
211static void metaserver_failed(void)
212{
213 if (!persistent_meta_connection) {
214 con_puts(C_METAERROR, _("Not reporting to the metaserver in this game."));
215 con_flush();
216
217 server_close_meta();
218 } else {
219 con_puts(C_METAERROR, _("Metaserver connection currently failing."));
220 meta_retry_wait = 1;
221 }
222}
223
224/*********************************************************************/
227static inline bool meta_insert_setting(struct netfile_post *post,
228 const char *set_name)
229{
230 const struct setting *pset = setting_by_name(set_name);
231 char buf[256];
232
233 fc_assert_ret_val_msg(NULL != pset, FALSE,
234 "Setting \"%s\" not found!", set_name);
235 netfile_add_form_str(post, "vn[]", setting_name(pset));
236 netfile_add_form_str(post, "vv[]",
237 setting_value_name(pset, FALSE, buf, sizeof(buf)));
238 return TRUE;
239}
240
241/*********************************************************************/
244static void send_metaserver_post(void *arg)
245{
246 struct netfile_post *post = (struct netfile_post *) arg;
247 char *addr;
248
249 if (srvarg.bind_meta_addr != NULL) {
250 addr = srvarg.bind_meta_addr;
251 } else {
252 addr = srvarg.bind_addr;
253 }
254
255 if (!netfile_send_post(srvarg.metaserver_addr, post, NULL, NULL, addr)) {
256 con_puts(C_METAERROR, _("Error connecting to metaserver"));
257 metaserver_failed();
258 }
259
260 netfile_close_post(post);
261}
262
263/*********************************************************************/
266static bool send_to_metaserver(enum meta_flag flag)
267{
268 int players = 0;
269 int humans = 0;
270 char host[512];
271 char state[20];
272 char rs[256];
273 struct netfile_post *post;
274
275 switch (server_state()) {
276 case S_S_INITIAL:
277 sz_strlcpy(state, "Pregame");
278 break;
279 case S_S_RUNNING:
280 sz_strlcpy(state, "Running");
281 break;
282 case S_S_OVER:
283 sz_strlcpy(state, "Game Ended");
284 break;
285 }
286
287 /* get hostname */
288 if (srvarg.identity_name[0] != '\0') {
289 sz_strlcpy(host, srvarg.identity_name);
290 } else if (fc_gethostname(host, sizeof(host)) != 0) {
291 sz_strlcpy(host, "unknown");
292 }
293
294 if (game.control.version[0] != '\0') {
295 fc_snprintf(rs, sizeof(rs), "%s %s", game.control.name, game.control.version);
296 } else {
297 sz_strlcpy(rs, game.control.name);
298 }
299
300 /* Freed in metaserver thread function send_metaserver_post() */
301 post = netfile_start_post();
302
303 netfile_add_form_str(post, "host", host);
304 netfile_add_form_int(post, "port", srvarg.port);
305 netfile_add_form_str(post, "state", state);
306 netfile_add_form_str(post, "ruleset", rs);
307
308 if (flag == META_GOODBYE) {
309 netfile_add_form_int(post, "bye", 1);
310 } else {
311 const char *srvtype = get_meta_type_string();
312
313 if (srvtype != NULL) {
314 netfile_add_form_str(post, "type", srvtype);
315 }
316 netfile_add_form_str(post, "version", VERSION_STRING);
317 netfile_add_form_str(post, "patches",
318 get_meta_patches_string());
319 netfile_add_form_str(post, "capability", our_capability);
320
321 netfile_add_form_str(post, "serverid", srvarg.serverid);
322 netfile_add_form_str(post, "message",
323 get_meta_message_string());
324
325 /* NOTE: send info for ALL players or none at all. */
326 if (normal_player_count() == 0) {
327 netfile_add_form_int(post, "dropplrs", 1);
328 } else {
329 players = 0; /* a counter for players_available */
330 humans = 0;
331
332 players_iterate(plr) {
333 bool is_player_available = TRUE;
334 char type[15];
335 struct connection *pconn = conn_by_user(plr->username);
336
337 if (!plr->is_alive) {
338 sz_strlcpy(type, "Dead");
339 } else if (is_barbarian(plr)) {
340 sz_strlcpy(type, "Barbarian");
341 } else if (is_ai(plr)) {
342 sz_strlcpy(type, "A.I.");
343 } else if (is_human(plr)) {
344 sz_strlcpy(type, "Human");
345 } else {
346 sz_strlcpy(type, "-");
347 }
348
349 netfile_add_form_str(post, "plu[]", plr->username);
350 netfile_add_form_str(post, "plt[]", type);
351 netfile_add_form_str(post, "pll[]", player_name(plr));
352 netfile_add_form_str(post, "pln[]",
353 plr->nation != NO_NATION_SELECTED
354 ? nation_plural_for_player(plr)
355 : "none");
356 netfile_add_form_str(post, "plf[]",
357 plr->nation != NO_NATION_SELECTED
358 ? nation_of_player(plr)->flag_graphic_str
359 : "none");
360 netfile_add_form_str(post, "plh[]",
361 pconn ? pconn->addr : "");
362
363 /* is this player available to take?
364 * TODO: there's some duplication here with
365 * stdinhand.c:is_allowed_to_take() */
366 if (is_barbarian(plr) && !strchr(game.server.allow_take, 'b')) {
367 is_player_available = FALSE;
368 } else if (!plr->is_alive && !strchr(game.server.allow_take, 'd')) {
369 is_player_available = FALSE;
370 } else if (is_ai(plr)
371 && !strchr(game.server.allow_take,
372 (game.info.is_new_game ? 'A' : 'a'))) {
373 is_player_available = FALSE;
374 } else if (is_human(plr)
375 && !strchr(game.server.allow_take,
376 (game.info.is_new_game ? 'H' : 'h'))) {
377 is_player_available = FALSE;
378 }
379
380 if (pconn) {
381 is_player_available = FALSE;
382 }
383
384 if (is_player_available) {
385 players++;
386 }
387
388 if (is_human(plr) && plr->is_alive) {
389 humans++;
390 }
391 } players_iterate_end;
392
393 /* send the number of available players. */
394 netfile_add_form_int(post, "available", players);
395 netfile_add_form_int(post, "humans", humans);
396 }
397
398 /* Send some variables: should be listed in inverted order? */
399 {
400 static const char *settings[] = {
401 "timeout", "endturn", "minplayers", "maxplayers",
402 "aifill", "allowtake", "generator"
403 };
404 int i;
405
406 for (i = 0; i < ARRAY_SIZE(settings); i++) {
407 meta_insert_setting(post, settings[i]);
408 }
409
410 /* HACK: send the most determinant setting for the map size. */
411 switch (wld.map.server.mapsize) {
412 case MAPSIZE_FULLSIZE:
413 meta_insert_setting(post, "size");
414 break;
415 case MAPSIZE_PLAYER:
416 meta_insert_setting(post, "tilesperplayer");
417 break;
418 case MAPSIZE_XYSIZE:
419 meta_insert_setting(post, "xsize");
420 meta_insert_setting(post, "ysize");
421 break;
422 }
423 }
424
425 /* Turn and year. */
426 netfile_add_form_str(post, "vn[]", "turn");
427 netfile_add_form_int(post, "vv[]", game.info.turn);
428 netfile_add_form_str(post, "vn[]", "year");
429
430 if (server_state() != S_S_INITIAL) {
431 netfile_add_form_int(post, "vv[]", game.info.year);
432 } else {
433 netfile_add_form_str(post, "vv[]", "Calendar not set up");
434 }
435 }
436
437 if (meta_srv_thread != NULL) {
438 /* Previously started thread */
439 fc_thread_wait(meta_srv_thread);
440 } else {
441 meta_srv_thread = fc_malloc(sizeof(meta_srv_thread));
442 }
443
444 /* Send POST in new thread */
445 fc_thread_start(meta_srv_thread, &send_metaserver_post, post);
446
447 return TRUE;
448}
449#endif /* FREECIV_META_ENABLED */
450
451/*********************************************************************/
454 void server_close_meta(void)
455{
456 server_is_open = FALSE;
457 persistent_meta_connection = FALSE;
458}
459
460/*********************************************************************/
463 bool server_open_meta(bool persistent)
464{
465 if (meta_patches[0] == '\0') {
466 set_meta_patches_string(default_meta_patches_string());
467 }
468 if (meta_message[0] == '\0') {
469 set_meta_message_string(default_meta_message_string());
470 }
471
472 server_is_open = TRUE;
473 persistent_meta_connection = persistent;
474 meta_retry_wait = 0;
475
476 return TRUE;
477}
478
479/*********************************************************************/
482 bool is_metaserver_open(void)
483{
484 return server_is_open;
485}
486
487/*********************************************************************/
490 bool send_server_info_to_metaserver(enum meta_flag flag)
491{
492#ifndef FREECIV_META_ENABLED
493
494 return FALSE;
495
496#else /* FREECIV_META_ENABLED */
497
498 static struct timer *last_send_timer = NULL;
499 static bool want_update;
500 int since_previous;
501
502 if (!server_is_open) {
503 return FALSE;
504 }
505
506 /* Persistent connection temporary failures handling */
507 if (meta_retry_wait > 0) {
508 if (meta_retry_wait++ > 5) {
509 meta_retry_wait = 0;
510 } else {
511 return FALSE;
512 }
513 }
514
515 /* if we're bidding farewell, ignore all timers */
516 if (flag == META_GOODBYE) {
517 if (last_send_timer) {
518 timer_destroy(last_send_timer);
519 last_send_timer = NULL;
520 }
521 send_to_metaserver(flag);
522
523 /* Wait metaserver thread to finish */
524 fc_thread_wait(meta_srv_thread);
525 free(meta_srv_thread);
526 meta_srv_thread = NULL;
527
528 return TRUE;
529 }
530
531 if (last_send_timer != NULL) {
532 since_previous = timer_read_seconds(last_send_timer);
533
534 /* Don't allow the user to spam the metaserver with updates */
535 if (since_previous < METASERVER_MIN_UPDATE_INTERVAL) {
536 if (flag == META_INFO) {
537 want_update = TRUE; /* We couldn't update now, but update a.s.a.p. */
538 }
539 return FALSE;
540 }
541 } else {
542 since_previous = MAX(METASERVER_REFRESH_INTERVAL + 1,
543 METASERVER_MIN_UPDATE_INTERVAL + 1);
544 }
545
546 /* If we're asking for a refresh, only do so if
547 * we've exceeded the refresh interval */
548 if ((flag == META_REFRESH) && !want_update
549 && since_previous < METASERVER_REFRESH_INTERVAL) {
550 return FALSE;
551 }
552
553 /* Start a new timer if we haven't already */
554 if (last_send_timer == NULL) {
555 last_send_timer = timer_new(TIMER_USER, TIMER_ACTIVE);
556 }
557
558 timer_clear(last_send_timer);
559 timer_start(last_send_timer);
560 want_update = FALSE;
561
562 return send_to_metaserver(flag);
563#endif /* FREECIV_META_ENABLED */
564}
our_capability
const char *const our_capability
Definition capstr.c:32
capstr.h
conn_by_user
struct connection * conn_by_user(const char *user_name)
Definition connection.c:376
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:57
wld
struct world wld
Definition game.c:58
game.h
type
GType type
Definition repodlgs.c:1312
persistent
static GtkWidget * persistent
Definition rallypointdlg.c:40
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:151
set_meta_patches_string
void set_meta_patches_string(const char *string)
Definition meta.c:171
get_user_meta_message_string
const char * get_user_meta_message_string(void)
Definition meta.c:136
is_metaserver_open
bool is_metaserver_open(void)
Definition meta.c:482
persistent_meta_connection
static bool persistent_meta_connection
Definition meta.c:69
meta_addr_port
char * meta_addr_port(void)
Definition meta.c:202
set_meta_message_string
void set_meta_message_string(const char *string)
Definition meta.c:179
meta_message
static char meta_message[256]
Definition meta.c:73
default_meta_message_string
const char * default_meta_message_string(void)
Definition meta.c:90
server_close_meta
void server_close_meta(void)
Definition meta.c:454
default_meta_patches_string
const char * default_meta_patches_string(void)
Definition meta.c:82
get_meta_message_string
const char * get_meta_message_string(void)
Definition meta.c:114
send_server_info_to_metaserver
bool send_server_info_to_metaserver(enum meta_flag flag)
Definition meta.c:490
meta_retry_wait
static int meta_retry_wait
Definition meta.c:70
server_is_open
static bool server_is_open
Definition meta.c:68
server_open_meta
bool server_open_meta(bool persistent)
Definition meta.c:463
get_meta_patches_string
const char * get_meta_patches_string(void)
Definition meta.c:106
set_user_meta_message_string
void set_user_meta_message_string(const char *string)
Definition meta.c:187
meta_patches
static char meta_patches[256]
Definition meta.c:72
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:443
nation_plural_for_player
const char * nation_plural_for_player(const struct player *pplayer)
Definition nation.c:177
NO_NATION_SELECTED
#define NO_NATION_SELECTED
Definition nation.h:29
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:886
players_iterate_end
#define players_iterate_end
Definition player.h:535
players_iterate
#define players_iterate(_pplayer)
Definition player.h:530
is_barbarian
static bool is_barbarian(const struct player *pplayer)
Definition player.h:488
is_ai
#define is_ai(plr)
Definition player.h:234
is_human
#define is_human(plr)
Definition player.h:233
normal_player_count
int normal_player_count(void)
Definition plrhand.c:3034
plrhand.h
setting_by_name
struct setting * setting_by_name(const char *name)
Definition settings.c:3138
setting_value_name
const char * setting_value_name(const struct setting *pset, bool pretty, char *buf, size_t buf_len)
Definition settings.c:4066
settings
static struct setting settings[]
Definition settings.c:1378
setting_name
const char * setting_name(const struct setting *pset)
Definition settings.c:3162
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:173
server_state
enum server_states server_state(void)
Definition srv_main.c:323
srv_main.h
civ_game::type
char type[20]
Definition game.h:263
civ_game::server
struct civ_game::@30::@34 server
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:262
civ_game::meta_info
struct civ_game::@30::@34::@37 meta_info
civ_game::allow_take
char allow_take[MAX_LEN_ALLOW_TAKE]
Definition game.h:238
civ_map::mapsize
enum mapsize_type mapsize
Definition map_types.h:85
civ_map::server
struct civ_map::@41::@43 server
connection
Definition connection.h:141
connection::addr
char addr[MAX_LEN_ADDR]
Definition connection.h:170
netfile_post
Definition netfile.c:39
packet_game_info::is_new_game
bool is_new_game
Definition packets_gen.h:186
packet_game_info::turn
int turn
Definition packets_gen.h:241
packet_game_info::year
int year
Definition packets_gen.h:243
packet_ruleset_control::version
char version[MAX_LEN_NAME]
Definition packets_gen.h:1482
packet_ruleset_control::name
char name[MAX_LEN_NAME]
Definition packets_gen.h:1481
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:88
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:969
fc_gethostname
int fc_gethostname(char *buf, size_t len)
Definition support.c:1016
support.h
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:161
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
timer_new
struct timer * timer_new(enum timer_timetype type, enum timer_use use)
Definition timing.c:157
timer_clear
void timer_clear(struct timer *t)
Definition timing.c:212
timer_destroy
void timer_destroy(struct timer *t)
Definition timing.c:191
timer_start
void timer_start(struct timer *t)
Definition timing.c:224
timer_read_seconds
double timer_read_seconds(struct timer *t)
Definition timing.c:344
timing.h
TIMER_ACTIVE
@ TIMER_ACTIVE
Definition timing.h:45
TIMER_USER
@ TIMER_USER
Definition timing.h:41
version.h