Freeciv-3.2
Loading...
Searching...
No Matches
connectdlg_common.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 2004 - The Freeciv Project
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 <fcntl.h>
21#include <stdio.h>
22#include <signal.h> /* SIGTERM and kill */
23#include <string.h>
24#include <time.h>
25
26#ifdef FREECIV_MSWINDOWS
27#include <windows.h>
28#endif
29
30#ifdef FREECIV_HAVE_SYS_TYPES_H
31#include <sys/types.h> /* fchmod */
32#endif
33
34#ifdef HAVE_SYS_STAT_H
35#include <sys/stat.h> /* fchmod */
36#endif
37
38#ifdef HAVE_SYS_WAIT_H
39#include <sys/wait.h>
40#endif
41
42/* utility */
43#include "astring.h"
44#include "capability.h"
45#include "deprecations.h"
46#include "fciconv.h"
47#include "fcintl.h"
48#include "ioz.h"
49#include "log.h"
50#include "mem.h"
51#include "netintf.h"
52#include "rand.h"
53#include "registry.h"
54#include "shared.h"
55#include "support.h"
56
57/* client */
58#include "attribute.h"
59#include "client_main.h"
60#include "climisc.h"
61#include "clinet.h" /* connect_to_server() */
62#include <packhand_gen.h> /* <> so looked from the build directory first. */
63
64#include "chatline_common.h"
65#include "connectdlg_g.h"
66#include "connectdlg_common.h"
67#include "tilespec.h"
68
69#define WAIT_BETWEEN_TRIES 100000 /* usecs */
70
71#ifdef FREECIV_PATIENT_CONNECT
72#define NUMBER_OF_TRIES 10000
73#else /* FREECIV_PATIENT_CONNECT */
74#define NUMBER_OF_TRIES 500
75#endif /* FREECIV_PATIENT_CONNECT */
76
77#if defined(HAVE_WORKING_FORK) && !defined(FREECIV_MSWINDOWS)
78/* We are yet to see FREECIV_MSWINDOWS setup where even HAVE_WORKING_FORK would
79 * mean fork() that actually works for us. */
80#define HAVE_USABLE_FORK
81#endif
82
83#ifdef HAVE_USABLE_FORK
84static pid_t server_pid = -1;
85#elif FREECIV_MSWINDOWS
88#endif /* HAVE_USABLE_FORK || FREECIV_MSWINDOWS */
90
92static bool client_has_hack = FALSE;
93
95
96/**************************************************************************
97 The general chain of events:
98
99 Two distinct paths are taken depending on the choice of mode:
100
101 If the user selects the multi-player mode, then a packet_req_join_game
102 packet is sent to the server. It is either successful or not. The end.
103
104 If the user selects a single-player mode (either a new game or a save game)
105 then:
106 1. the packet_req_join_game is sent.
107 2. on receipt, if we can join, then a challenge packet is sent to the
108 server, so we can get hack level control.
109 3. if we can't get hack, then we get dumped to multi-player mode. If
110 we can, then:
111 a. for a new game, we send a series of packet_generic_message packets
112 with commands to start the game.
113 b. for a saved game, we send the load command with a
114 packet_generic_message, then we send a PACKET_PLAYER_LIST_REQUEST.
115 the response to this request will tell us if the game was loaded or
116 not. if not, then we send another load command. if so, then we send
117 a series of packet_generic_message packets with commands to start
118 the game.
119**************************************************************************/
120
121/**********************************************************************/
125{
126 if (server_quitting) {
127 return FALSE;
128 }
129#ifdef HAVE_USABLE_FORK
130 return (server_pid > 0);
131#elif FREECIV_MSWINDOWS
133#else
134 return FALSE; /* We've been unable to start one! */
135#endif
136}
137
138/**********************************************************************/
142{
143 return client_has_hack;
144}
145
146/**********************************************************************/
154{
155#ifdef HAVE_USABLE_FORK
156 if (server_quitting && server_pid > 0) {
157 /* Already asked to /quit.
158 * If it didn't do that, kill it. */
159 if (waitpid(server_pid, NULL, WUNTRACED) <= 0) {
162 }
163 server_pid = -1;
165 }
166#elif FREECIV_MSWINDOWS
168 /* Already asked to /quit.
169 * If it didn't do that, kill it. */
174 }
178 }
179#endif /* FREECIV_MSWINDOWS || HAVE_USABLE_FORK */
180
181 if (is_server_running()) {
183 /* This does a "soft" shutdown of the server by sending a /quit.
184 *
185 * This is useful when closing the client or disconnecting because it
186 * doesn't kill the server prematurely. In particular, killing the
187 * server in the middle of a save can have disastrous results. This
188 * method tells the server to quit on its own. This is safer from a
189 * game perspective, but more dangerous because if the kill fails the
190 * server will be left running.
191 *
192 * Another potential problem is because this function is called atexit
193 * it could potentially be called when we're connected to an unowned
194 * server. In this case we don't want to kill it. */
195 send_chat("/quit");
197 } else if (force) {
198 /* Either we already disconnected, or we didn't get control of the
199 * server. In either case, the only thing to do is a "hard" kill of
200 * the server. */
201#ifdef HAVE_USABLE_FORK
204 server_pid = -1;
205#elif FREECIV_MSWINDOWS
210 }
213#endif /* FREECIV_MSWINDOWS || HAVE_USABLE_FORK */
215 }
216 }
218}
219
220/**********************************************************************/
225{
226#if !defined(HAVE_USABLE_FORK) && !defined(FREECIV_MSWINDOWS)
227 /* Can't do much without fork */
228 return FALSE;
229#else /* HAVE_USABLE_FORK || FREECIV_MSWINDOWS */
230 char buf[512];
231 int connect_tries = 0;
234 char *storage;
235 char *ruleset;
236
237#if !defined(HAVE_USABLE_FORK)
238 /* Above also implies that this is FREECIV_MSWINDOWS ->
239 * Windows that can't use fork() */
242
243 char options[1024];
244 char *depr;
245 char rsparam[256];
246#ifdef FREECIV_DEBUG
247 char cmdline1[512];
248#ifndef FREECIV_WEB
249 char cmdline2[512];
250#endif /* FREECIV_WEB */
251#endif /* FREECIV_DEBUG */
252 char cmdline3[512];
253 char cmdline4[512];
254 char logcmdline[512];
255 char scriptcmdline[512];
256 char savefilecmdline[512];
257 char savescmdline[512];
258 char scenscmdline[512];
259#endif /* !HAVE_USABLE_FORK -> FREECIV_MSWINDOWS */
260
261#ifdef FREECIV_IPV6_SUPPORT
263#else
265#endif /* FREECIV_IPV6_SUPPORT */
266
267 /* Only one server (forked from this client) shall be running at a time */
268 /* This also resets client_has_hack. */
270
271 output_window_append(ftc_client, _("Starting local server..."));
272
273 /* Find a free port */
274 /* Mitigate the risk of ending up with the port already
275 * used by standalone server on Windows where this is known to be buggy
276 * by not starting from DEFAULT_SOCK_PORT but from one higher. */
278 DEFAULT_SOCK_PORT + 1 + 10000,
279 family, "localhost", TRUE);
280
281 if (internal_server_port < 0) {
282 output_window_append(ftc_client, _("Couldn't start the server."));
284 _("You'll have to start one manually. Sorry..."));
285 return FALSE;
286 }
287
289 if (storage == NULL) {
290 output_window_append(ftc_client, _("Cannot find freeciv storage directory"));
292 _("You'll have to start server manually. Sorry..."));
293 return FALSE;
294 }
295
297
298#ifdef HAVE_USABLE_FORK
299 {
300 int argc = 0;
301 const int max_nargs = 25;
302 char *argv[max_nargs + 1];
303 char port_buf[32];
304 char dbg_lvl_buf[32]; /* Do not move this inside the block where it gets filled,
305 * it's needed via the argv[x] pointer later on, so must
306 * remain in scope. */
307 bool log_to_dev_null = FALSE;
308
309 /* Set up the command-line parameters. */
311 fc_snprintf(savesdir, sizeof(savesdir), "%s" DIR_SEPARATOR "saves", storage);
312 fc_snprintf(scensdir, sizeof(scensdir), "%s" DIR_SEPARATOR "scenarios", storage);
313#ifdef FREECIV_WEB
314 argv[argc++] = "freeciv-web";
315#else /* FREECIV_WEB */
316 argv[argc++] = "freeciv-server";
317#endif /* FREECIV_WEB */
318 argv[argc++] = "-p";
319 argv[argc++] = port_buf;
320 argv[argc++] = "--bind";
321 argv[argc++] = "localhost";
322 argv[argc++] = "-q";
323 argv[argc++] = "1";
324 argv[argc++] = "-e";
325 argv[argc++] = "--saves";
326 argv[argc++] = savesdir;
327 argv[argc++] = "--scenarios";
328 argv[argc++] = scensdir;
329 argv[argc++] = "-A";
330 argv[argc++] = "none";
331 if (logfile) {
333
334 argv[argc++] = "--debug";
336 argv[argc++] = dbg_lvl_buf;
337 argv[argc++] = "--log";
338 argv[argc++] = logfile;
339 }
340 if (scriptfile) {
341 argv[argc++] = "--read";
342 argv[argc++] = scriptfile;
343 }
344 if (savefile) {
345 argv[argc++] = "--file";
346 argv[argc++] = savefile;
347 }
349 argv[argc++] = "--warnings";
350 }
351 if (ruleset != NULL) {
352 argv[argc++] = "--ruleset";
353 argv[argc++] = ruleset;
354 }
355 argv[argc] = NULL;
357
358 {
360 int i;
361
362 for (i = 1; i < argc; i++) {
363 astr_add(&srv_cmdline_opts, i == 1 ? "%s" : " %s", argv[i]);
364 }
365 log_verbose("Arguments to spawned server: %s",
368 }
369
370 server_pid = fork();
372
373 if (server_pid == 0) {
374 int fd;
375
376 /* Inside the child */
377
378 /* Avoid terminal spam, but still make server output available */
379 fclose(stdout);
380 fclose(stderr);
381
382 if (!logfile) {
384 fd = open("/dev/null", O_WRONLY);
385 } else {
386 /* FIXME: include the port to avoid duplication? */
387 fd = open(logfile, O_WRONLY | O_CREAT | O_APPEND, 0644);
388 }
389
390 if (fd != 1) {
391 dup2(fd, 1);
392 }
393 if (fd != 2) {
394 dup2(fd, 2);
395 }
396 if (!log_to_dev_null) {
397 fchmod(1, 0644);
398 }
399
400 /* If it's still attached to our terminal, things get messed up,
401 but freeciv-server needs *something* */
402 fclose(stdin);
403 fd = open("/dev/null", O_RDONLY);
404 if (fd != 0) {
405 dup2(fd, 0);
406 }
407
408 /* These won't return on success */
409#ifdef FREECIV_DEBUG
410 /* Search under current directory (what ever that happens to be)
411 * only in debug builds. This allows running freeciv directly from build
412 * tree, but could be considered security risk in release builds. */
413#ifdef FREECIV_WEB
414 execvp("./server/freeciv-web", argv);
415#else /* FREECIV_WEB */
416#ifdef MESON_BUILD
417 execvp("./freeciv-server", argv);
418#else /* MESON_BUILD */
419 execvp("./fcser", argv);
420 execvp("./server/freeciv-server", argv);
421#endif /* MESON_BUILD */
422#endif /* FREECIV_WEB */
423#endif /* FREECIV_DEBUG */
424#ifdef FREECIV_WEB
425 execvp(BINDIR "/freeciv-web", argv);
426 execvp("freeciv-web", argv);
427#else /* FREECIV_WEB */
428 execvp(BINDIR "/freeciv-server", argv);
429 execvp("freeciv-server", argv);
430#endif /* FREECIV_WEB */
431
432 /* This line is only reached if freeciv-server cannot be started,
433 * so we kill the forked process.
434 * Calling exit here is dangerous due to X11 problems (async replies) */
435 _exit(1);
436 }
437 }
438#else /* HAVE_USABLE_FORK */
439#ifdef FREECIV_MSWINDOWS
440 if (logfile) {
443 NULL,
444 OPEN_ALWAYS, 0, NULL);
445 }
446
447 ZeroMemory(&si, sizeof(si));
448 si.cb = sizeof(si);
449 si.hStdOutput = loghandle;
450 si.hStdInput = INVALID_HANDLE_VALUE;
451 si.hStdError = loghandle;
452 si.dwFlags = STARTF_USESTDHANDLES;
453
454 /* Set up the command-line parameters. */
455 logcmdline[0] = 0;
456 scriptcmdline[0] = 0;
457 savefilecmdline[0] = 0;
458
459 /* The server expects command line arguments to be in local encoding */
460 if (logfile) {
464
465 fc_snprintf(logcmdline, sizeof(logcmdline), " --debug %s --log %s",
469 }
470 if (scriptfile) {
473
474 fc_snprintf(scriptcmdline, sizeof(scriptcmdline), " --read %s",
477 }
478 if (savefile) {
481
482 fc_snprintf(savefilecmdline, sizeof(savefilecmdline), " --file %s",
485 }
486
487 fc_snprintf(savesdir, sizeof(savesdir), "%s" DIR_SEPARATOR "saves", storage);
489
490 fc_snprintf(scensdir, sizeof(scensdir), "%s" DIR_SEPARATOR "scenarios", storage);
492
494 depr = " --warnings";
495 } else {
496 depr = "";
497 }
498 if (ruleset != NULL) {
499 fc_snprintf(rsparam, sizeof(rsparam), " --ruleset %s", ruleset);
500 } else {
501 rsparam[0] = '\0';
502 }
503
504 fc_snprintf(options, sizeof(options),
505 "-p %d --bind localhost -q 1 -e%s%s%s --saves \"%s\" "
506 "--scenarios \"%s\" -A none %s%s",
509#ifdef FREECIV_DEBUG
510#ifdef FREECIV_WEB
512 "./server/freeciv-web %s", options);
513#else /* FREECIV_WEB */
514 fc_snprintf(cmdline1, sizeof(cmdline1), "./fcser %s", options);
516 "./server/freeciv-server %s", options);
517#endif /* FREECIV_WEB */
518#endif /* FREECIV_DEBUG */
519#ifdef FREECIV_WEB
521 BINDIR "/freeciv-web %s", options);
523 "freeciv-web %s", options);
524#else /* FREECIV_WEB */
526 BINDIR "/freeciv-server %s", options);
528 "freeciv-server %s", options);
529#endif /* FREECIV_WEB */
530
531 if (
535 NULL, NULL, &si, &pi)
539 NULL, NULL, &si, &pi)
540#endif /* FREECIV_WEB */
541 &&
542#endif /* FREECIV_DEBUG */
545 NULL, NULL, &si, &pi)
548 NULL, NULL, &si, &pi)) {
549 log_error("Failed to start server process.");
550#ifdef FREECIV_DEBUG
551 log_verbose("Tried with commandline: '%s'", cmdline1);
552 log_verbose("Tried with commandline: '%s'", cmdline2);
553#endif /* FREECIV_DEBUG */
554 log_verbose("Tried with commandline: '%s'", cmdline3);
555 log_verbose("Tried with commandline: '%s'", cmdline4);
556 output_window_append(ftc_client, _("Couldn't start the server."));
558 _("You'll have to start one manually. Sorry..."));
559 return FALSE;
560 }
561
562 log_verbose("Arguments to spawned server: %s", options);
563
564 server_process = pi.hProcess;
565
566#endif /* FREECIV_MSWINDOWS */
567#endif /* HAVE_USABLE_FORK */
568
569 /* A reasonable number of tries */
571 buf, sizeof(buf)) == -1) {
573#ifdef HAVE_USABLE_FORK
574#ifndef FREECIV_MSWINDOWS
575 if (waitpid(server_pid, NULL, WNOHANG) != 0) {
576 break;
577 }
578#endif /* FREECIV_MSWINDOWS */
579#endif /* HAVE_USABLE_FORK */
581 log_error("Last error from connect attempts: '%s'", buf);
582 break;
583 }
584 }
585
586 /* Weird, but could happen, if server doesn't support new startup stuff
587 * capabilities won't help us here... */
588 if (!client.conn.used) {
589 /* Possible that server is still running. kill it */
591
592 log_error("Failed to connect to spawned server!");
593 output_window_append(ftc_client, _("Couldn't connect to the server."));
595 _("We probably couldn't start it from here."));
597 _("You'll have to start one manually. Sorry..."));
598
599 return FALSE;
600 }
601
602 /* We set the topology to match the view.
603 *
604 * When a typical player launches a game, they want the map orientation
605 * to match the tileset orientation. So if you use an isometric tileset,
606 * you get an iso-map and for a classic tileset you get a classic map.
607 *
608 * This works also with hex maps. A hex map always has
609 * tileset_is_isometric(tileset) return TRUE. An iso-hex map has
610 * tileset_hex_height(tileset) != 0, while a non-iso hex map
611 * has tileset_hex_width(tileset) != 0.
612 *
613 * Setting the option here is a bit of a hack, but so long as the client
614 * has sufficient permissions to do so (it doesn't have HACK access yet) it
615 * is safe enough. Note that if you load a savegame the topology will be
616 * set but then overwritten during the load.
617 *
618 * Don't send it now, it will be sent to the server when receiving the
619 * server setting infos. */
620 {
621 char topobuf[16];
622 bool iso = FALSE;
624
625 if (hh == 0 && tileset_is_isometric(tileset)) {
626 fc_strlcpy(topobuf, "ISO", sizeof(topobuf));
627 iso = TRUE;
628 }
629
630 if (0 < hh || 0 < tileset_hex_width(tileset)) {
631 if (iso) {
632 fc_strlcat(topobuf, "|HEX", sizeof(topobuf));
633 } else {
634 fc_strlcpy(topobuf, "HEX", sizeof(topobuf));
635 }
636 } else if (!iso) {
637 /* Empty value */
638 topobuf[0] = '\0';
639 }
640
642 }
643
644 return TRUE;
645#endif /* HAVE_USABLE_FORK || FREECIV_MSWINDOWS */
646}
647
648/**********************************************************************/
651static void randomize_string(char *str, size_t n)
652{
653 const char chars[] =
654 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
655 int i;
656
657 for (i = 0; i < n - 1; i++) {
658 str[i] = chars[fc_rand(sizeof(chars) - 1)];
659 }
660 str[i] = '\0';
661}
662
663/**********************************************************************/
671void send_client_wants_hack(const char *filename)
672{
673 if (filename[0] != '\0') {
675 struct section_file *file;
676 const char *sdir = freeciv_storage_dir();
677
678 if (sdir == NULL) {
679 return;
680 }
681
682 if (!is_safe_filename(filename)) {
683 return;
684 }
685
686 if (!make_dir(sdir)) {
687 log_error("Couldn't create storage directory for token.");
688 return;
689 }
690
692 "%s" DIR_SEPARATOR "%s", sdir, filename);
693
694 /* Generate an authentication token */
695 randomize_string(req.token, sizeof(req.token));
696
697 file = secfile_new(FALSE);
698 secfile_insert_str(file, req.token, "challenge.token");
699 if (!secfile_save(file, challenge_fullname, 0, FZ_PLAIN)) {
700 log_error("Couldn't write token to temporary file: %s",
702 /* FIXME: We need to destroy the secfile, but do we really
703 * want also to send the network packet after this? */
704 }
705 secfile_destroy(file);
706
707 /* Tell the server what we put into the file */
709 }
710}
711
712/**********************************************************************/
715void handle_single_want_hack_reply(bool you_have_hack)
716{
717 /* Remove challenge file */
718 if (challenge_fullname[0] != '\0') {
719 if (fc_remove(challenge_fullname) == -1) {
720 log_error("Couldn't remove temporary file: %s", challenge_fullname);
721 }
722 challenge_fullname[0] = '\0';
723 }
724
725 if (you_have_hack) {
727 _("Established control over the server. "
728 "You have command access level 'hack'."));
730 } else if (is_server_running()) {
731 /* Only output this if we started the server and we NEED hack */
733 _("Failed to obtain the required access "
734 "level to take control of the server. "
735 "Attempting to shut down server."));
737 }
738}
739
740/**********************************************************************/
743void send_save_game(const char *filename)
744{
746
747 if (filename) {
748 send_chat_printf("/save %s", filename);
749 } else {
750 send_chat("/save");
751 }
752}
753
754/**********************************************************************/
758{
759 char *rulesets[packet->ruleset_count];
760 int i;
761 size_t suf_len = strlen(RULESET_SUFFIX);
762
763 for (i = 0; i < packet->ruleset_count; i++) {
764 size_t len = strlen(packet->rulesets[i]);
765
766 rulesets[i] = fc_strdup(packet->rulesets[i]);
767
768 if (len > suf_len
769 && strcmp(rulesets[i] + len - suf_len, RULESET_SUFFIX) == 0) {
770 rulesets[i][len - suf_len] = '\0';
771 }
772 }
773 set_rulesets(packet->ruleset_count, rulesets);
774
775 for (i = 0; i < packet->ruleset_count; i++) {
776 free(rulesets[i]);
777 }
778}
779
780/**********************************************************************/
784void set_ruleset(const char *ruleset)
785{
786 struct packet_ruleset_select packet;
787
788 fc_snprintf(packet.modpack, sizeof(packet.modpack), "%s", ruleset);
789
791}
void astr_free(struct astring *astr)
Definition astring.c:153
void astr_add(struct astring *astr, const char *format,...)
Definition astring.c:287
#define str
Definition astring.c:76
#define n
Definition astring.c:77
static const char * astr_str(const struct astring *astr) fc__attribute((nonnull(1)))
Definition astring.h:93
#define ASTRING_INIT
Definition astring.h:44
void attribute_flush(void)
Definition attribute.c:327
int send_chat_printf(const char *format,...)
int send_chat(const char *message)
void output_window_append(const struct ft_color color, const char *featured_text)
char user_name[512]
char * logfile
struct civclient client
char * scriptfile
char * savefile
int connect_to_server(const char *username, const char *hostname, int port, char *errbuf, int errbufsize)
Definition clinet.c:249
char * incite_cost
Definition comments.c:74
#define NUMBER_OF_TRIES
void handle_ruleset_choices(const struct packet_ruleset_choices *packet)
bool server_quitting
void handle_single_want_hack_reply(bool you_have_hack)
void send_client_wants_hack(const char *filename)
static bool client_has_hack
int internal_server_port
void send_save_game(const char *filename)
static void randomize_string(char *str, size_t n)
#define WAIT_BETWEEN_TRIES
void set_ruleset(const char *ruleset)
bool is_server_running(void)
void client_kill_server(bool force)
bool client_start_server(void)
bool can_client_access_hack(void)
static char challenge_fullname[MAX_LEN_PATH]
bool are_deprecation_warnings_enabled(void)
static char * ruleset
Definition fc_manual.c:159
#define RULESET_SUFFIX
Definition fc_types.h:417
char * internal_to_local_string_buffer(const char *text, char *buf, size_t bufsz)
char * internal_to_local_string_malloc(const char *text)
#define _(String)
Definition fcintl.h:67
const struct ft_color ftc_client
void set_rulesets(int num_rulesets, char **rulesets)
Definition pages.c:3570
@ FZ_PLAIN
Definition ioz.h:37
const char * log_level_name(enum log_level lvl)
Definition log.c:330
enum log_level log_get_level(void)
Definition log.c:322
#define log_verbose(message,...)
Definition log.h:109
#define fc_assert(condition)
Definition log.h:176
log_level
Definition log.h:28
#define log_error(message,...)
Definition log.h:103
#define fc_strdup(str)
Definition mem.h:43
fc_addr_family
Definition net_types.h:61
@ FC_ADDR_IPV4
Definition net_types.h:62
@ FC_ADDR_ANY
Definition net_types.h:64
int find_next_free_port(int starting_port, int highest_port, enum fc_addr_family family, char *net_interface, bool not_avail_ok)
Definition netintf.c:553
void desired_settable_option_update(const char *op_name, const char *op_value, bool allow_replace)
Definition options.c:5613
int send_packet_ruleset_select(struct connection *pc, const struct packet_ruleset_select *packet)
int send_packet_single_want_hack_req(struct connection *pc, const struct packet_single_want_hack_req *packet)
int len
Definition packhand.c:127
#define fc_rand(_size)
Definition rand.h:56
struct section_file * secfile_new(bool allow_duplicates)
void secfile_destroy(struct section_file *secfile)
bool secfile_save(const struct section_file *secfile, const char *filename, int compression_level, enum fz_method compression_method)
#define secfile_insert_str(secfile, string, path,...)
bool make_dir(const char *pathname)
Definition shared.c:1779
bool is_safe_filename(const char *name)
Definition shared.c:253
char * freeciv_storage_dir(void)
Definition shared.c:678
#define DIR_SEPARATOR
Definition shared.h:127
#define MAX_LEN_PATH
Definition shared.h:32
struct connection conn
Definition client_main.h:96
char rulesets[MAX_NUM_RULESETS][MAX_RULESET_NAME_LENGTH]
char modpack[MAX_RULESET_NAME_LENGTH]
char token[MAX_LEN_NAME]
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:974
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:791
void fc_usleep(unsigned long usec)
Definition support.c:641
size_t fc_strlcat(char *dest, const char *src, size_t n)
Definition support.c:836
int fc_remove(const char *filename)
Definition support.c:557
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
int tileset_hex_width(const struct tileset *t)
Definition tilespec.c:721
bool tileset_is_isometric(const struct tileset *t)
Definition tilespec.c:712
int tileset_hex_height(const struct tileset *t)
Definition tilespec.c:730
char * tileset_what_ruleset(struct tileset *t)
Definition tilespec.c:7558