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_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) {
441 loghandle = CreateFile(logfile, GENERIC_WRITE,
442 FILE_SHARE_READ | FILE_SHARE_WRITE,
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) {
461 char *logfile_in_local_encoding =
462 internal_to_local_string_malloc(logfile);
463 enum log_level llvl = log_get_level();
464
465 fc_snprintf(logcmdline, sizeof(logcmdline), " --debug %s --log %s",
466 log_level_name(llvl),
467 logfile_in_local_encoding);
468 free(logfile_in_local_encoding);
469 }
470 if (scriptfile) {
471 char *scriptfile_in_local_encoding =
472 internal_to_local_string_malloc(scriptfile);
473
474 fc_snprintf(scriptcmdline, sizeof(scriptcmdline), " --read %s",
475 scriptfile_in_local_encoding);
476 free(scriptfile_in_local_encoding);
477 }
478 if (savefile) {
479 char *savefile_in_local_encoding =
480 internal_to_local_string_malloc(savefile);
481
482 fc_snprintf(savefilecmdline, sizeof(savefilecmdline), " --file %s",
483 savefile_in_local_encoding);
484 free(savefile_in_local_encoding);
485 }
486
487 fc_snprintf(savesdir, sizeof(savesdir), "%s" DIR_SEPARATOR "saves", storage);
488 internal_to_local_string_buffer(savesdir, savescmdline, sizeof(savescmdline));
489
490 fc_snprintf(scensdir, sizeof(scensdir), "%s" DIR_SEPARATOR "scenarios", storage);
491 internal_to_local_string_buffer(scensdir, scenscmdline, sizeof(scenscmdline));
492
493 if (are_deprecation_warnings_enabled()) {
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",
507 internal_server_port, logcmdline, scriptcmdline, savefilecmdline,
508 savescmdline, scenscmdline, rsparam, depr);
509#ifdef FREECIV_DEBUG
510#ifdef FREECIV_WEB
511 fc_snprintf(cmdline1, sizeof(cmdline1),
512 "./server/freeciv-web %s", options);
513#else /* FREECIV_WEB */
514 fc_snprintf(cmdline1, sizeof(cmdline1), "./fcser %s", options);
515 fc_snprintf(cmdline2, sizeof(cmdline2),
516 "./server/freeciv-server %s", options);
517#endif /* FREECIV_WEB */
518#endif /* FREECIV_DEBUG */
519#ifdef FREECIV_WEB
520 fc_snprintf(cmdline3, sizeof(cmdline2),
521 BINDIR "/freeciv-web %s", options);
522 fc_snprintf(cmdline4, sizeof(cmdline3),
523 "freeciv-web %s", options);
524#else /* FREECIV_WEB */
525 fc_snprintf(cmdline3, sizeof(cmdline3),
526 BINDIR "/freeciv-server %s", options);
527 fc_snprintf(cmdline4, sizeof(cmdline4),
528 "freeciv-server %s", options);
529#endif /* FREECIV_WEB */
530
531 if (
532#ifdef FREECIV_DEBUG
533 !CreateProcess(NULL, cmdline1, NULL, NULL, TRUE,
534 DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
535 NULL, NULL, &si, &pi)
536#ifndef FREECIV_WEB
537 && !CreateProcess(NULL, cmdline2, NULL, NULL, TRUE,
538 DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
539 NULL, NULL, &si, &pi)
540#endif /* FREECIV_WEB */
541 &&
542#endif /* FREECIV_DEBUG */
543 !CreateProcess(NULL, cmdline3, NULL, NULL, TRUE,
544 DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
545 NULL, NULL, &si, &pi)
546 && !CreateProcess(NULL, cmdline4, NULL, NULL, TRUE,
547 DETACHED_PROCESS | NORMAL_PRIORITY_CLASS,
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."));
557 output_window_append(ftc_client,
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 */
570 while (connect_to_server(user_name, "localhost", internal_server_port,
571 buf, sizeof(buf)) == -1) {
572 fc_usleep(WAIT_BETWEEN_TRIES);
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 */
580 if (connect_tries++ > NUMBER_OF_TRIES) {
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 */
590 client_kill_server(TRUE);
591
592 log_error("Failed to connect to spawned server!");
593 output_window_append(ftc_client, _("Couldn't connect to the server."));
594 output_window_append(ftc_client,
595 _("We probably couldn't start it from here."));
596 output_window_append(ftc_client,
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 * In both cases the map wraps in the X direction by default.
608 *
609 * This works with hex maps too now. A hex map always has
610 * tileset_is_isometric(tileset) return TRUE. An iso-hex map has
611 * tileset_hex_height(tileset) != 0, while a non-iso hex map
612 * has tileset_hex_width(tileset) != 0.
613 *
614 * Setting the option here is a bit of a hack, but so long as the client
615 * has sufficient permissions to do so (it doesn't have HACK access yet) it
616 * is safe enough. Note that if you load a savegame the topology will be
617 * set but then overwritten during the load.
618 *
619 * Don't send it now, it will be sent to the server when receiving the
620 * server setting infos. */
621 {
622 char topobuf[16];
623
624 fc_strlcpy(topobuf, "WRAPX", sizeof(topobuf));
625 if (tileset_is_isometric(tileset) && 0 == tileset_hex_height(tileset)) {
626 fc_strlcat(topobuf, "|ISO", sizeof(topobuf));
627 }
628 if (0 < tileset_hex_width(tileset) || 0 < tileset_hex_height(tileset)) {
629 fc_strlcat(topobuf, "|HEX", sizeof(topobuf));
630 }
631 desired_settable_option_update("topology", topobuf, FALSE);
632 }
633
634 return TRUE;
635#endif /* HAVE_USABLE_FORK || FREECIV_MSWINDOWS */
636}
637
638/**********************************************************************/
641 static void randomize_string(char *str, size_t n)
642{
643 const char chars[] =
644 "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
645 int i;
646
647 for (i = 0; i < n - 1; i++) {
648 str[i] = chars[fc_rand(sizeof(chars) - 1)];
649 }
650 str[i] = '\0';
651}
652
653/**********************************************************************/
661 void send_client_wants_hack(const char *filename)
662{
663 if (filename[0] != '\0') {
664 struct packet_single_want_hack_req req;
665 struct section_file *file;
666 const char *sdir = freeciv_storage_dir();
667
668 if (sdir == NULL) {
669 return;
670 }
671
672 if (!is_safe_filename(filename)) {
673 return;
674 }
675
676 if (!make_dir(sdir)) {
677 log_error("Couldn't create storage directory for token.");
678 return;
679 }
680
681 fc_snprintf(challenge_fullname, sizeof(challenge_fullname),
682 "%s" DIR_SEPARATOR "%s", sdir, filename);
683
684 /* Generate an authentication token */
685 randomize_string(req.token, sizeof(req.token));
686
687 file = secfile_new(FALSE);
688 secfile_insert_str(file, req.token, "challenge.token");
689 if (!secfile_save(file, challenge_fullname, 0, FZ_PLAIN)) {
690 log_error("Couldn't write token to temporary file: %s",
691 challenge_fullname);
692 /* FIXME: We need to destroy the secfile, but do we really
693 * want also to send the network packet after this? */
694 }
695 secfile_destroy(file);
696
697 /* Tell the server what we put into the file */
698 send_packet_single_want_hack_req(&client.conn, &req);
699 }
700}
701
702/**********************************************************************/
705 void handle_single_want_hack_reply(bool you_have_hack)
706{
707 /* remove challenge file */
708 if (challenge_fullname[0] != '\0') {
709 if (fc_remove(challenge_fullname) == -1) {
710 log_error("Couldn't remove temporary file: %s", challenge_fullname);
711 }
712 challenge_fullname[0] = '\0';
713 }
714
715 if (you_have_hack) {
716 output_window_append(ftc_client,
717 _("Established control over the server. "
718 "You have command access level 'hack'."));
719 client_has_hack = TRUE;
720 } else if (is_server_running()) {
721 /* only output this if we started the server and we NEED hack */
722 output_window_append(ftc_client,
723 _("Failed to obtain the required access "
724 "level to take control of the server. "
725 "Attempting to shut down server."));
726 client_kill_server(TRUE);
727 }
728}
729
730/**********************************************************************/
733 void send_save_game(const char *filename)
734{
735 attribute_flush();
736
737 if (filename) {
738 send_chat_printf("/save %s", filename);
739 } else {
740 send_chat("/save");
741 }
742}
743
744/**********************************************************************/
747 void handle_ruleset_choices(const struct packet_ruleset_choices *packet)
748{
749 char *rulesets[packet->ruleset_count];
750 int i;
751 size_t suf_len = strlen(RULESET_SUFFIX);
752
753 for (i = 0; i < packet->ruleset_count; i++) {
754 size_t len = strlen(packet->rulesets[i]);
755
756 rulesets[i] = fc_strdup(packet->rulesets[i]);
757
758 if (len > suf_len
759 && strcmp(rulesets[i] + len - suf_len, RULESET_SUFFIX) == 0) {
760 rulesets[i][len - suf_len] = '\0';
761 }
762 }
763 set_rulesets(packet->ruleset_count, rulesets);
764
765 for (i = 0; i < packet->ruleset_count; i++) {
766 free(rulesets[i]);
767 }
768}
769
770/**********************************************************************/
774 void set_ruleset(const char *ruleset)
775{
776 char buf[4096];
777
778 fc_snprintf(buf, sizeof(buf), "/read %s%s", ruleset, RULESET_SUFFIX);
779 log_debug("Executing '%s'", buf);
780 send_chat(buf);
781}
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:747
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:705
send_client_wants_hack
void send_client_wants_hack(const char *filename)
Definition connectdlg_common.c:661
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:733
randomize_string
static void randomize_string(char *str, size_t n)
Definition connectdlg_common.c:641
WAIT_BETWEEN_TRIES
#define WAIT_BETWEEN_TRIES
Definition connectdlg_common.c:69
set_ruleset
void set_ruleset(const char *ruleset)
Definition connectdlg_common.c:774
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:3570
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