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
68static bool server_is_open = FALSE;
70static int meta_retry_wait = 0;
71
72static char meta_patches[256] = "";
73static char meta_message[256] = "";
74
75#ifdef FREECIV_META_ENABLED
76static fc_thread *meta_srv_thread = NULL;
77#endif /* FREECIV_META_ENABLED */
78
79/*********************************************************************/
83{
84 return "none";
85}
86
87/*********************************************************************/
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/*********************************************************************/
106const char *get_meta_patches_string(void)
107{
108 return meta_patches;
109}
110
111/*********************************************************************/
114const 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/*********************************************************************/
137{
138 if (game.server.meta_info.user_message[0] != '\0') {
140 }
141
142 return NULL;
143}
144
145/*********************************************************************/
151void 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/*********************************************************************/
171void set_meta_patches_string(const char *string)
172{
173 sz_strlcpy(meta_patches, string);
174}
175
176/*********************************************************************/
179void set_meta_message_string(const char *string)
180{
181 sz_strlcpy(meta_message, string);
182}
183
184/*********************************************************************/
187void set_user_meta_message_string(const char *string)
188{
189 if (string != NULL && string[0] != '\0') {
192 } else {
193 /* Remove user meta message. We will use automatic messages instead */
196 }
197}
198
199/*********************************************************************/
202char *meta_addr_port(void)
203{
204 return srvarg.metaserver_addr;
205}
206
207#ifdef FREECIV_META_ENABLED
208/*********************************************************************/
211static void metaserver_failed(void)
212{
214 con_puts(C_METAERROR, _("Not reporting to the metaserver in this game."));
215 con_flush();
216
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') {
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 {
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",
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",
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
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 }
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/*********************************************************************/
459
460/*********************************************************************/
478
479/*********************************************************************/
483{
484 return server_is_open;
485}
486
487/*********************************************************************/
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,
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}
const char *const our_capability
Definition capstr.c:32
struct connection * conn_by_user(const char *user_name)
Definition connection.c:376
void con_flush(void)
Definition console.c:243
void con_puts(enum rfc_status rfc_status, const char *str)
Definition console.c:226
@ C_METAERROR
Definition console.h:46
#define _(String)
Definition fcintl.h:67
int fc_thread_start(fc_thread *thread, void(*function)(void *arg), void *arg)
void fc_thread_wait(fc_thread *thread)
struct civ_game game
Definition game.c:57
struct world wld
Definition game.c:58
GType type
Definition repodlgs.c:1312
static GtkWidget * persistent
#define fc_assert_ret_val_msg(condition, val, message,...)
Definition log.h:208
@ MAPSIZE_FULLSIZE
Definition map_types.h:39
@ MAPSIZE_PLAYER
Definition map_types.h:40
@ MAPSIZE_XYSIZE
Definition map_types.h:43
#define fc_malloc(sz)
Definition mem.h:34
void maybe_automatic_meta_message(const char *automatic)
Definition meta.c:151
void set_meta_patches_string(const char *string)
Definition meta.c:171
const char * get_user_meta_message_string(void)
Definition meta.c:136
bool is_metaserver_open(void)
Definition meta.c:482
static bool persistent_meta_connection
Definition meta.c:69
char * meta_addr_port(void)
Definition meta.c:202
void set_meta_message_string(const char *string)
Definition meta.c:179
static char meta_message[256]
Definition meta.c:73
const char * default_meta_message_string(void)
Definition meta.c:90
void server_close_meta(void)
Definition meta.c:454
const char * default_meta_patches_string(void)
Definition meta.c:82
const char * get_meta_message_string(void)
Definition meta.c:114
bool send_server_info_to_metaserver(enum meta_flag flag)
Definition meta.c:490
static int meta_retry_wait
Definition meta.c:70
static bool server_is_open
Definition meta.c:68
bool server_open_meta(bool persistent)
Definition meta.c:463
const char * get_meta_patches_string(void)
Definition meta.c:106
void set_user_meta_message_string(const char *string)
Definition meta.c:187
static char meta_patches[256]
Definition meta.c:72
#define METASERVER_REFRESH_INTERVAL
Definition meta.h:22
#define METASERVER_MIN_UPDATE_INTERVAL
Definition meta.h:23
meta_flag
Definition meta.h:25
@ META_GOODBYE
Definition meta.h:28
@ META_INFO
Definition meta.h:26
@ META_REFRESH
Definition meta.h:27
struct nation_type * nation_of_player(const struct player *pplayer)
Definition nation.c:443
const char * nation_plural_for_player(const struct player *pplayer)
Definition nation.c:177
#define NO_NATION_SELECTED
Definition nation.h:29
void netfile_close_post(struct netfile_post *post)
Definition netfile.c:244
struct netfile_post * netfile_start_post(void)
Definition netfile.c:197
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
void netfile_add_form_int(struct netfile_post *post, const char *name, const int val)
Definition netfile.c:232
void netfile_add_form_str(struct netfile_post *post, const char *name, const char *val)
Definition netfile.c:211
const char * player_name(const struct player *pplayer)
Definition player.c:886
#define players_iterate_end
Definition player.h:535
#define players_iterate(_pplayer)
Definition player.h:530
static bool is_barbarian(const struct player *pplayer)
Definition player.h:488
#define is_ai(plr)
Definition player.h:234
#define is_human(plr)
Definition player.h:233
int normal_player_count(void)
Definition plrhand.c:3034
struct setting * setting_by_name(const char *name)
Definition settings.c:3138
const char * setting_value_name(const struct setting *pset, bool pretty, char *buf, size_t buf_len)
Definition settings.c:4066
static struct setting settings[]
Definition settings.c:1378
const char * setting_name(const struct setting *pset)
Definition settings.c:3162
#define ARRAY_SIZE(x)
Definition shared.h:85
#define MAX(x, y)
Definition shared.h:54
struct server_arguments srvarg
Definition srv_main.c:173
enum server_states server_state(void)
Definition srv_main.c:323
char type[20]
Definition game.h:263
struct civ_game::@30::@34 server
struct packet_ruleset_control control
Definition game.h:83
struct packet_game_info info
Definition game.h:89
char user_message[256]
Definition game.h:262
struct civ_game::@30::@34::@37 meta_info
char allow_take[MAX_LEN_ALLOW_TAKE]
Definition game.h:238
enum mapsize_type mapsize
Definition map_types.h:85
struct civ_map::@41::@43 server
char addr[MAX_LEN_ADDR]
Definition connection.h:170
Definition netfile.c:39
char version[MAX_LEN_NAME]
char name[MAX_LEN_NAME]
char * bind_addr
Definition srv_main.h:34
char metaserver_addr[256]
Definition srv_main.h:29
char * bind_meta_addr
Definition srv_main.h:38
char serverid[256]
Definition srv_main.h:49
char identity_name[256]
Definition srv_main.h:31
Definition timing.c:81
struct civ_map map
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
int fc_gethostname(char *buf, size_t len)
Definition support.c:1016
#define sz_strlcpy(dest, src)
Definition support.h:167
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
struct timer * timer_new(enum timer_timetype type, enum timer_use use)
Definition timing.c:157
void timer_clear(struct timer *t)
Definition timing.c:212
void timer_destroy(struct timer *t)
Definition timing.c:191
void timer_start(struct timer *t)
Definition timing.c:224
double timer_read_seconds(struct timer *t)
Definition timing.c:344
@ TIMER_ACTIVE
Definition timing.h:45
@ TIMER_USER
Definition timing.h:41