Freeciv-3.1: /fast/freeciv/nightly/S3_1/client/connectdlg_common.c Source File

Freeciv-3.1

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
86HANDLE server_process = INVALID_HANDLE_VALUE;
87HANDLE loghandle = INVALID_HANDLE_VALUE;
88#endif /* HAVE_USABLE_FORK || FREECIV_MSWINDOWS */
89 bool server_quitting = FALSE;
90
91 static char challenge_fullname[MAX_LEN_PATH];
92 static bool client_has_hack = FALSE;
93
94 int internal_server_port;
95
96/**************************************************************************
97The general chain of events:
98
99Two distinct paths are taken depending on the choice of mode:
100
101if the user selects the multi- player mode, then a packet_req_join_game
102packet is sent to the server. It is either successful or not. The end.
103
104If the user selects a single- player mode (either a new game or a save game)
105then:
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/**********************************************************************/
124 bool is_server_running(void)
125{
126 if (server_quitting) {
127 return FALSE;
128 }
129#ifdef HAVE_USABLE_FORK
130 return (server_pid > 0);
131#elif FREECIV_MSWINDOWS
132 return (server_process != INVALID_HANDLE_VALUE);
133#else
134 return FALSE; /* We've been unable to start one! */
135#endif
136}
137
138/**********************************************************************/
141 bool can_client_access_hack(void)
142{
143 return client_has_hack;
144}
145
146/**********************************************************************/
153 void client_kill_server(bool force)
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) {
160 kill(server_pid, SIGTERM);
161 waitpid(server_pid, NULL, WUNTRACED);
162 }
163 server_pid = -1;
164 server_quitting = FALSE;
165 }
166#elif FREECIV_MSWINDOWS
167 if (server_quitting && server_process != INVALID_HANDLE_VALUE) {
168 /* Already asked to /quit.
169 * If it didn't do that, kill it. */
170 TerminateProcess(server_process, 0);
171 CloseHandle(server_process);
172 if (loghandle != INVALID_HANDLE_VALUE) {
173 CloseHandle(loghandle);
174 }
175 server_process = INVALID_HANDLE_VALUE;
176 loghandle = INVALID_HANDLE_VALUE;
177 server_quitting = FALSE;
178 }
179#endif /* FREECIV_MSWINDOWS || HAVE_USABLE_FORK */
180
181 if (is_server_running()) {
182 if (client.conn.used && client_has_hack) {
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");
196 server_quitting = TRUE;
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
202 kill(server_pid, SIGTERM);
203 waitpid(server_pid, NULL, WUNTRACED);
204 server_pid = -1;
205#elif FREECIV_MSWINDOWS
206 TerminateProcess(server_process, 0);
207 CloseHandle(server_process);
208 if (loghandle != INVALID_HANDLE_VALUE) {
209 CloseHandle(loghandle);
210 }
211 server_process = INVALID_HANDLE_VALUE;
212 loghandle = INVALID_HANDLE_VALUE;
213#endif /* FREECIV_MSWINDOWS || HAVE_USABLE_FORK */
214 server_quitting = FALSE;
215 }
216 }
217 client_has_hack = FALSE;
218}
219
220/**********************************************************************/
224 bool client_start_server(void)
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;
232 char savesdir[MAX_LEN_PATH];
233 char scensdir[MAX_LEN_PATH];
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() */
240 STARTUPINFO si;
241 PROCESS_INFORMATION pi;
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
262 enum fc_addr_family family = FC_ADDR_ANY;
263#else
264 enum fc_addr_family family = FC_ADDR_IPV4;
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. */
269 client_kill_server(TRUE);
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. */
277 internal_server_port = find_next_free_port(DEFAULT_SOCK_PORT + 1,
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."));
283 output_window_append(ftc_client,
284 _("You'll have to start one manually. Sorry..."));
285 return FALSE;
286 }
287
288 storage = freeciv_storage_dir();
289 if (storage == NULL) {
290 output_window_append(ftc_client, _("Cannot find freeciv storage directory"));
291 output_window_append(ftc_client,
292 _("You'll have to start server manually. Sorry..."));
293 return FALSE;
294 }
295
296 ruleset = tileset_what_ruleset(tileset);
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. */
310 fc_snprintf(port_buf, sizeof(port_buf), "%d", internal_server_port);
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) {
332 enum log_level llvl = log_get_level();
333
334 argv[argc++] = "--debug";
335 fc_snprintf(dbg_lvl_buf, sizeof(dbg_lvl_buf), "%s", log_level_name(llvl));
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 }
348 if (are_deprecation_warnings_enabled()) {
349 argv[argc++] = "--warnings";
350 }
351 if (ruleset != NULL) {
352 argv[argc++] = "--ruleset";
353 argv[argc++] = ruleset;
354 }
355 argv[argc] = NULL;
356 fc_assert(argc <= max_nargs);
357
358 {
359 struct astring srv_cmdline_opts = ASTRING_INIT;
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",
366 astr_str(&srv_cmdline_opts));
367 astr_free(&srv_cmdline_opts);
368 }
369
370 server_pid = fork();
371 server_quitting = FALSE;
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) {
383 log_to_dev_null = TRUE;
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_APPIMAGE
410 char srvpath[2048];
411
412 fc_snprintf(srvpath, sizeof(srvpath), "%s/usr/bin/freeciv-server",
413 getenv("APPDIR"));
414 execvp(srvpath, argv);
415#else /* FREECIV_APPIMAGE */
416#ifdef FREECIV_DEBUG
417 /* Search under current directory (what ever that happens to be)
418 * only in debug builds. This allows running freeciv directly from build
419 * tree, but could be considered security risk in release builds. */
420#ifdef FREECIV_WEB
421 execvp("./server/freeciv-web", argv);
422#else /* FREECIV_WEB */
423#ifdef MESON_BUILD
424 execvp("./freeciv-server", argv);
425#else /* MESON_BUILD */
426 execvp("./fcser", argv);
427 execvp("./server/freeciv-server", argv);
428#endif /* MESON_BUILD */
429#endif /* FREECIV_WEB */
430#endif /* FREECIV_DEBUG */
431#ifdef FREECIV_WEB
432 execvp(BINDIR "/freeciv-web", argv);
433 execvp("freeciv-web", argv);
434#else /* FREECIV_WEB */
435 execvp(BINDIR "/freeciv-server", argv);
436 execvp("freeciv-server", argv);
437#endif /* FREECIV_WEB */
438#endif /* FREECIV_APPIMAGE */
439
440 /* This line is only reached if freeciv-server cannot be started,
441 * so we kill the forked process.
442 * Calling exit here is dangerous due to X11 problems (async replies) */
443 _exit(1);
444 }
445 }
446#else /* HAVE_USABLE_FORK */
447#ifdef FREECIV_MSWINDOWS
448 if (logfile) {
449 loghandle = CreateFile(logfile, GENERIC_WRITE,
450 FILE_SHARE_READ | FILE_SHARE_WRITE,
451 NULL,
452 OPEN_ALWAYS, 0, NULL);
453 }
454
455 ZeroMemory(&si, sizeof(si));
456 si.cb = sizeof(si);
457 si.hStdOutput = loghandle;
458 si.hStdInput = INVALID_HANDLE_VALUE;
459 si.hStdError = loghandle;
460 si.dwFlags = STARTF_USESTDHANDLES;
461
462 /* Set up the command-line parameters. */
463 logcmdline[0] = 0;
464 scriptcmdline[0] = 0;
465 savefilecmdline[0] = 0;
466
467 /* the server expects command line arguments to be in local encoding */
468 if (logfile) {
469 char *logfile_in_local_encoding =
470 internal_to_local_string_malloc(logfile);
471 enum log_level llvl = log_get_level();
472
473 fc_snprintf(logcmdline, sizeof(logcmdline), " --debug %s --log %s",
474 log_level_name(llvl),
475 logfile_in_local_encoding);
476 free(logfile_in_local_encoding);
477 }
478 if (scriptfile) {
479 char *scriptfile_in_local_encoding =
480 internal_to_local_string_malloc(scriptfile);
481
482 fc_snprintf(scriptcmdline, sizeof(scriptcmdline), " --read %s",
483 scriptfile_in_local_encoding);
484 free(scriptfile_in_local_encoding);
485 }
486 if (savefile) {
487 char *savefile_in_local_encoding =
488 internal_to_local_string_malloc(savefile);
489
490 fc_snprintf(savefilecmdline, sizeof(savefilecmdline), " --file %s",
491 savefile_in_local_encoding);
492 free(savefile_in_local_encoding);
493 }
494
495 fc_snprintf(savesdir, sizeof(savesdir), "%s" DIR_SEPARATOR "saves", storage);
496 internal_to_local_string_buffer(savesdir, savescmdline, sizeof(savescmdline));
497
498 fc_snprintf(scensdir, sizeof(scensdir), "%s" DIR_SEPARATOR "scenarios", storage);
499 internal_to_local_string_buffer(scensdir, scenscmdline, sizeof(scenscmdline));
500
501 if (are_deprecation_warnings_enabled()) {
502 depr = " --warnings";
503 } else {
504 depr = "";
505 }
506 if (ruleset != NULL) {
507 fc_snprintf(rsparam, sizeof(rsparam), " --ruleset %s", ruleset);
508 } else {
509 rsparam[0] = '\0';
510 }
511
512 fc_snprintf(options, sizeof(options),
513 "-p %d --bind localhost -q 1 -e%s%s%s --saves \"%s\" "
514 "--scenarios \"%s\" -A none %s%s",
515 internal_server_port, logcmdline, scriptcmdline, savefilecmdline,
516 savescmdline, scenscmdline, rsparam, depr);
517#ifdef FREECIV_DEBUG
518#ifdef FREECIV_WEB
519 fc_snprintf(cmdline1, sizeof(cmdline1),
520 "./server/freeciv-web %s", options);
521#else /* FREECIV_WEB */
522 fc_snprintf(cmdline1, sizeof(cmdline1), "./fcser %s", options);
523 fc_snprintf(cmdline2, sizeof(cmdline2),
524 "./server/freeciv-server %s", options);
525#endif /* FREECIV_WEB */
526#endif /* FREECIV_DEBUG */
527#ifdef FREECIV_WEB
528 fc_snprintf(cmdline3, sizeof(cmdline2),
529 BINDIR "/freeciv-web %s", options);
530 fc_snprintf(cmdline4, sizeof(cmdline3),
531 "freeciv-web %s", options);
532#else /* FREECIV_WEB */
533 fc_snprintf(cmdline3, sizeof(cmdline3),
534 BINDIR "/freeciv-server %s", options);
535 fc_snprintf(cmdline4, sizeof(cmdline4),
536 "freeciv-server %s", options);
537#endif /* FREECIV_WEB */
538
539 if (
540#ifdef FREECIV_DEBUG
541 !CreateProcess(NULL, cmdline1, NULL, NULL, TRUE,
542 DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
543 NULL, NULL, &si, &pi)
544#ifndef FREECIV_WEB
545 && !CreateProcess(NULL, cmdline2, NULL, NULL, TRUE,
546 DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
547 NULL, NULL, &si, &pi)
548#endif /* FREECIV_WEB */
549 &&
550#endif /* FREECIV_DEBUG */
551 !CreateProcess(NULL, cmdline3, NULL, NULL, TRUE,
552 DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
553 NULL, NULL, &si, &pi)
554 && !CreateProcess(NULL, cmdline4, NULL, NULL, TRUE,
555 DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
556 NULL, NULL, &si, &pi)) {
557 log_error("Failed to start server process.");
558#ifdef FREECIV_DEBUG
559 log_verbose("Tried with commandline: '%s'", cmdline1);
560 log_verbose("Tried with commandline: '%s'", cmdline2);
561#endif /* FREECIV_DEBUG */
562 log_verbose("Tried with commandline: '%s'", cmdline3);
563 log_verbose("Tried with commandline: '%s'", cmdline4);
564 output_window_append(ftc_client, _("Couldn't start the server."));
565 output_window_append(ftc_client,
566 _("You'll have to start one manually. Sorry..."));
567 return FALSE;
568 }
569
570 log_verbose("Arguments to spawned server: %s", options);
571
572 server_process = pi.hProcess;
573
574#endif /* FREECIV_MSWINDOWS */
575#endif /* HAVE_USABLE_FORK */
576
577 /* a reasonable number of tries */
578 while (connect_to_server(user_name, "localhost", internal_server_port,
579 buf, sizeof(buf)) == -1) {
580 fc_usleep(WAIT_BETWEEN_TRIES);
581#ifdef HAVE_USABLE_FORK
582#ifndef FREECIV_MSWINDOWS
583 if (waitpid(server_pid, NULL, WNOHANG) != 0) {
584 break;
585 }
586#endif /* FREECIV_MSWINDOWS */
587#endif /* HAVE_USABLE_FORK */
588 if (connect_tries++ > NUMBER_OF_TRIES) {
589 log_error("Last error from connect attempts: '%s'", buf);
590 break;
591 }
592 }
593
594 /* weird, but could happen, if server doesn't support new startup stuff
595 * capabilities won't help us here... */
596 if (!client.conn.used) {
597 /* possible that server is still running. kill it */
598 client_kill_server(TRUE);
599
600 log_error("Failed to connect to spawned server!");
601 output_window_append(ftc_client, _("Couldn't connect to the server."));
602 output_window_append(ftc_client,
603 _("We probably couldn't start it from here."));
604 output_window_append(ftc_client,
605 _("You'll have to start one manually. Sorry..."));
606
607 return FALSE;
608 }
609
610 /* We set the topology to match the view.
611 *
612 * When a typical player launches a game, they want the map orientation
613 * to match the tileset orientation. So if you use an isometric tileset,
614 * you get an iso-map and for a classic tileset you get a classic map.
615 * In both cases the map wraps in the X direction by default.
616 *
617 * This works with hex maps too now. A hex map always has
618 * tileset_is_isometric(tileset) return TRUE. An iso-hex map has
619 * tileset_hex_height(tileset) != 0, while a non-iso hex map
620 * has tileset_hex_width(tileset) != 0.
621 *
622 * Setting the option here is a bit of a hack, but so long as the client
623 * has sufficient permissions to do so (it doesn't have HACK access yet) it
624 * is safe enough. Note that if you load a savegame the topology will be
625 * set but then overwritten during the load.
626 *
627 * Don't send it now, it will be sent to the server when receiving the
628 * server setting infos. */
629 {
630 char topobuf[16];
631
632 fc_strlcpy(topobuf, "WRAPX", sizeof(topobuf));
633 if (tileset_is_isometric(tileset) && 0 == tileset_hex_height(tileset)) {
634 fc_strlcat(topobuf, "|ISO", sizeof(topobuf));
635 }
636 if (0 < tileset_hex_width(tileset) || 0 < tileset_hex_height(tileset)) {
637 fc_strlcat(topobuf, "|HEX", sizeof(topobuf));
638 }
639 desired_settable_option_update("topology", topobuf, FALSE);
640 }
641
642 return TRUE;
643#endif /* HAVE_USABLE_FORK || FREECIV_MSWINDOWS */
644}
645
646/**********************************************************************/
649 static void randomize_string(char *str, size_t n)
650{
651 const char chars[] =
652 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
653 int i;
654
655 for (i = 0; i < n - 1; i++) {
656 str[i] = chars[fc_rand(sizeof(chars) - 1)];
657 }
658 str[i] = '\0';
659}
660
661/**********************************************************************/
669 void send_client_wants_hack(const char *filename)
670{
671 if (filename[0] != '\0') {
672 struct packet_single_want_hack_req req;
673 struct section_file *file;
674 const char *sdir = freeciv_storage_dir();
675
676 if (sdir == NULL) {
677 return;
678 }
679
680 if (!is_safe_filename(filename)) {
681 return;
682 }
683
684 if (!make_dir(sdir)) {
685 log_error("Couldn't create storage directory for token.");
686 return;
687 }
688
689 fc_snprintf(challenge_fullname, sizeof(challenge_fullname),
690 "%s" DIR_SEPARATOR "%s", sdir, filename);
691
692 /* Generate an authentication token */
693 randomize_string(req.token, sizeof(req.token));
694
695 file = secfile_new(FALSE);
696 secfile_insert_str(file, req.token, "challenge.token");
697 if (!secfile_save(file, challenge_fullname, 0, FZ_PLAIN)) {
698 log_error("Couldn't write token to temporary file: %s",
699 challenge_fullname);
700 /* FIXME: We need to destroy the secfile, but do we really
701 * want also to send the network packet after this? */
702 }
703 secfile_destroy(file);
704
705 /* Tell the server what we put into the file */
706 send_packet_single_want_hack_req(&client.conn, &req);
707 }
708}
709
710/**********************************************************************/
713 void handle_single_want_hack_reply(bool you_have_hack)
714{
715 /* remove challenge file */
716 if (challenge_fullname[0] != '\0') {
717 if (fc_remove(challenge_fullname) == -1) {
718 log_error("Couldn't remove temporary file: %s", challenge_fullname);
719 }
720 challenge_fullname[0] = '\0';
721 }
722
723 if (you_have_hack) {
724 output_window_append(ftc_client,
725 _("Established control over the server. "
726 "You have command access level 'hack'."));
727 client_has_hack = TRUE;
728 } else if (is_server_running()) {
729 /* only output this if we started the server and we NEED hack */
730 output_window_append(ftc_client,
731 _("Failed to obtain the required access "
732 "level to take control of the server. "
733 "Attempting to shut down server."));
734 client_kill_server(TRUE);
735 }
736}
737
738/**********************************************************************/
741 void send_save_game(const char *filename)
742{
743 attribute_flush();
744
745 if (filename) {
746 send_chat_printf("/save %s", filename);
747 } else {
748 send_chat("/save");
749 }
750}
751
752/**********************************************************************/
755 void handle_ruleset_choices(const struct packet_ruleset_choices *packet)
756{
757 char *rulesets[packet->ruleset_count];
758 int i;
759 size_t suf_len = strlen(RULESET_SUFFIX);
760
761 for (i = 0; i < packet->ruleset_count; i++) {
762 size_t len = strlen(packet->rulesets[i]);
763
764 rulesets[i] = fc_strdup(packet->rulesets[i]);
765
766 if (len > suf_len
767 && strcmp(rulesets[i] + len - suf_len, RULESET_SUFFIX) == 0) {
768 rulesets[i][len - suf_len] = '\0';
769 }
770 }
771 set_rulesets(packet->ruleset_count, rulesets);
772
773 for (i = 0; i < packet->ruleset_count; i++) {
774 free(rulesets[i]);
775 }
776}
777
778/**********************************************************************/
782 void set_ruleset(const char *ruleset)
783{
784 char buf[4096];
785
786 fc_snprintf(buf, sizeof(buf), "/read %s%s", ruleset, RULESET_SUFFIX);
787 log_debug("Executing '%s'", buf);
788 send_chat(buf);
789}
astr_free
void astr_free(struct astring *astr)
Definition astring.c:153
astr_add
void astr_add(struct astring *astr, const char *format,...)
Definition astring.c:287
str
#define str
Definition astring.c:76
n
#define n
Definition astring.c:77
astring.h
astr_str
static const char * astr_str(const struct astring *astr) fc__attribute((nonnull(1)))
Definition astring.h:93
ASTRING_INIT
#define ASTRING_INIT
Definition astring.h:44
attribute_flush
void attribute_flush(void)
Definition attribute.c:327
attribute.h
capability.h
send_chat_printf
int send_chat_printf(const char *format,...)
Definition chatline_common.c:55
send_chat
int send_chat(const char *message)
Definition chatline_common.c:46
output_window_append
void output_window_append(const struct ft_color color, const char *featured_text)
Definition chatline_common.c:104
chatline_common.h
ruleset
static char * ruleset
Definition civmanual.c:202
user_name
char user_name[512]
Definition client_main.c:141
logfile
char * logfile
Definition client_main.c:133
client
struct civclient client
Definition client_main.c:149
scriptfile
char * scriptfile
Definition client_main.c:134
savefile
char * savefile
Definition client_main.c:135
client_main.h
climisc.h
connect_to_server
int connect_to_server(const char *username, const char *hostname, int port, char *errbuf, int errbufsize)
Definition clinet.c:248
clinet.h
NUMBER_OF_TRIES
#define NUMBER_OF_TRIES
Definition connectdlg_common.c:74
handle_ruleset_choices
void handle_ruleset_choices(const struct packet_ruleset_choices *packet)
Definition connectdlg_common.c:755
server_quitting
bool server_quitting
Definition connectdlg_common.c:89
handle_single_want_hack_reply
void handle_single_want_hack_reply(bool you_have_hack)
Definition connectdlg_common.c:713
send_client_wants_hack
void send_client_wants_hack(const char *filename)
Definition connectdlg_common.c:669
client_has_hack
static bool client_has_hack
Definition connectdlg_common.c:92
internal_server_port
int internal_server_port
Definition connectdlg_common.c:94
send_save_game
void send_save_game(const char *filename)
Definition connectdlg_common.c:741
randomize_string
static void randomize_string(char *str, size_t n)
Definition connectdlg_common.c:649
WAIT_BETWEEN_TRIES
#define WAIT_BETWEEN_TRIES
Definition connectdlg_common.c:69
set_ruleset
void set_ruleset(const char *ruleset)
Definition connectdlg_common.c:782
is_server_running
bool is_server_running(void)
Definition connectdlg_common.c:124
client_kill_server
void client_kill_server(bool force)
Definition connectdlg_common.c:153
client_start_server
bool client_start_server(void)
Definition connectdlg_common.c:224
can_client_access_hack
bool can_client_access_hack(void)
Definition connectdlg_common.c:141
challenge_fullname
static char challenge_fullname[MAX_LEN_PATH]
Definition connectdlg_common.c:91
connectdlg_common.h
connectdlg_g.h
are_deprecation_warnings_enabled
bool are_deprecation_warnings_enabled(void)
Definition deprecations.c:43
deprecations.h
fc_prehdrs.h
RULESET_SUFFIX
#define RULESET_SUFFIX
Definition fc_types.h:384
fciconv.h
internal_to_local_string_buffer
char * internal_to_local_string_buffer(const char *text, char *buf, size_t bufsz)
internal_to_local_string_malloc
char * internal_to_local_string_malloc(const char *text)
fcintl.h
_
#define _(String)
Definition fcintl.h:67
ftc_client
const struct ft_color ftc_client
Definition featured_text.c:78
set_rulesets
void set_rulesets(int num_rulesets, char **rulesets)
Definition pages.c:3584
ioz.h
FZ_PLAIN
@ FZ_PLAIN
Definition ioz.h:37
log_level_name
const char * log_level_name(enum log_level lvl)
Definition log.c:330
log_get_level
enum log_level log_get_level(void)
Definition log.c:322
log.h
log_verbose
#define log_verbose(message,...)
Definition log.h:109
fc_assert
#define fc_assert(condition)
Definition log.h:176
log_debug
#define log_debug(message,...)
Definition log.h:115
log_level
log_level
Definition log.h:28
log_error
#define log_error(message,...)
Definition log.h:103
mem.h
fc_strdup
#define fc_strdup(str)
Definition mem.h:43
fc_addr_family
fc_addr_family
Definition net_types.h:61
FC_ADDR_IPV4
@ FC_ADDR_IPV4
Definition net_types.h:62
FC_ADDR_ANY
@ FC_ADDR_ANY
Definition net_types.h:64
find_next_free_port
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
netintf.h
desired_settable_option_update
void desired_settable_option_update(const char *op_name, const char *op_value, bool allow_replace)
Definition options.c:5599
send_packet_single_want_hack_req
int send_packet_single_want_hack_req(struct connection *pc, const struct packet_single_want_hack_req *packet)
Definition packets_gen.c:78847
len
int len
Definition packhand.c:125
packhand_gen.h
rand.h
fc_rand
#define fc_rand(_size)
Definition rand.h:34
registry.h
secfile_new
struct section_file * secfile_new(bool allow_duplicates)
Definition section_file.c:73
secfile_destroy
void secfile_destroy(struct section_file *secfile)
Definition section_file.c:95
secfile_save
bool secfile_save(const struct section_file *secfile, const char *filename, int compression_level, enum fz_method compression_method)
Definition registry_ini.c:641
secfile_insert_str
#define secfile_insert_str(secfile, string, path,...)
Definition registry_ini.h:170
make_dir
bool make_dir(const char *pathname)
Definition shared.c:1769
is_safe_filename
bool is_safe_filename(const char *name)
Definition shared.c:252
freeciv_storage_dir
char * freeciv_storage_dir(void)
Definition shared.c:672
shared.h
DIR_SEPARATOR
#define DIR_SEPARATOR
Definition shared.h:127
MAX_LEN_PATH
#define MAX_LEN_PATH
Definition shared.h:32
astring
Definition astring.h:36
civclient::conn
struct connection conn
Definition client_main.h:96
connection::used
bool used
Definition connection.h:144
packet_ruleset_choices
Definition packets_gen.h:1504
packet_ruleset_choices::ruleset_count
int ruleset_count
Definition packets_gen.h:1505
packet_ruleset_choices::rulesets
char rulesets[MAX_NUM_RULESETS][MAX_RULESET_NAME_LENGTH]
Definition packets_gen.h:1506
packet_single_want_hack_req
Definition packets_gen.h:1496
packet_single_want_hack_req::token
char token[MAX_LEN_NAME]
Definition packets_gen.h:1497
section_file
Definition section_file.h:36
tileset
Definition tilespec.c:459
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:969
fc_strlcpy
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:787
fc_usleep
void fc_usleep(unsigned long usec)
Definition support.c:640
fc_strlcat
size_t fc_strlcat(char *dest, const char *src, size_t n)
Definition support.c:832
fc_remove
int fc_remove(const char *filename)
Definition support.c:556
support.h
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
tileset_hex_width
int tileset_hex_width(const struct tileset *t)
Definition tilespec.c:684
tileset_is_isometric
bool tileset_is_isometric(const struct tileset *t)
Definition tilespec.c:675
tileset_hex_height
int tileset_hex_height(const struct tileset *t)
Definition tilespec.c:693
tileset_what_ruleset
char * tileset_what_ruleset(struct tileset *t)
Definition tilespec.c:7247
tilespec.h