Freeciv-3.3: /fast/freeciv/nightly/main/server/sernet.c Source File

Freeciv-3.3

Loading...
Searching...
No Matches
sernet.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 <errno.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <time.h>
25
26#ifdef FREECIV_HAVE_SYS_TYPES_H
27#include <sys/types.h>
28#endif
29#ifdef HAVE_SYS_SOCKET_H
30#include <sys/socket.h>
31#endif
32#ifdef HAVE_NETINET_IN_H
33#include <netinet/in.h>
34#endif
35#ifdef HAVE_ARPA_INET_H
36#include <arpa/inet.h>
37#endif
38#ifdef HAVE_NETDB_H
39#include <netdb.h>
40#endif
41#ifdef HAVE_PWD_H
42#include <pwd.h>
43#endif
44#ifdef FREECIV_HAVE_LIBREADLINE
45#include <readline/history.h>
46#include <readline/readline.h>
47#endif
48#ifdef HAVE_SYS_SELECT_H
49#include <sys/select.h>
50#endif
51#ifdef HAVE_SYS_TIME_H
52#include <sys/time.h>
53#endif
54#ifdef HAVE_SYS_UIO_H
55#include <sys/uio.h>
56#endif
57#ifdef HAVE_UNISTD_H
58#include <unistd.h>
59#endif
60
61/* utility */
62#include "capability.h"
63#include "fciconv.h"
64#include "fcintl.h"
65#include "log.h"
66#include "mem.h"
67#include "netintf.h"
68#include "shared.h"
69#include "support.h"
70#include "timing.h"
71
72/* common */
73#include "dataio.h"
74#include "events.h"
75#include "game.h"
76#include "packets.h"
77
78/* server/scripting */
79#include "script_server.h"
80
81/* server */
82#include "aiiface.h"
83#include "auth.h"
84#include "connecthand.h"
85#include "console.h"
86#include "meta.h"
87#include "plrhand.h"
88#include "srv_main.h"
89#include "stdinhand.h"
90#include "voting.h"
91
92#include "sernet.h"
93
94 static struct connection connections[MAX_NUM_CONNECTIONS];
95
96 static int *listen_socks;
97 static int listen_count;
98 static int socklan;
99
100#if defined(__VMS)
101# if defined(_VAX_)
102# define lib$stop LIB$STOP
103# define sys$qiow SYS$QIOW
104# define sys$assign SYS$ASSIGN
105# endif
106# include <descrip.h>
107# include <iodef.h>
108# include <stsdef.h>
109# include <starlet.h>
110# include <lib$routines.h>
111# include <efndef.h>
112 static unsigned long int tt_chan;
113 static char input_char = 0;
114 static char got_input = 0;
115 void user_interrupt_callback();
116#endif
117
118#define PROCESSING_TIME_STATISTICS 0
119
120static int server_accept_connection(int sockfd);
121static void start_processing_request(struct connection *pconn,
122 int request_id);
123static void finish_processing_request(struct connection *pconn);
124static void connection_ping(struct connection *pconn);
125static void send_ping_times_to_all(void);
126
127static void get_lanserver_announcement(void);
128static void send_lanserver_response(void);
129
130 static bool no_input = FALSE;
131
132/* Avoid compiler warning about defined, but unused function
133 * by defining it only when needed */
134#if defined(FREECIV_HAVE_LIBREADLINE) || \
135 (!defined(FREECIV_SOCKET_ZERO_NOT_STDIN) && !defined(FREECIV_HAVE_LIBREADLINE))
136/*************************************************************************/
139 static void handle_stdin_close(void)
140{
141 /* Note this function may be called even if FREECIV_SOCKET_ZERO_NOT_STDIN, so
142 * the preprocessor check has to come inside the function body. But
143 * perhaps we want to do this even when FREECIV_SOCKET_ZERO_NOT_STDIN? */
144#ifndef FREECIV_SOCKET_ZERO_NOT_STDIN
145 log_normal(_("Server cannot read standard input. Ignoring input."));
146 no_input = TRUE;
147#endif /* FREECIV_SOCKET_ZERO_NOT_STDIN */
148}
149
150#endif /* FREECIV_HAVE_LIBREADLINE || (!FREECIV_SOCKET_ZERO_NOT_STDIN && !FREECIV_HAVE_LIBREADLINE) */
151
152 static char *current_internal = NULL;
153
154#ifdef FREECIV_HAVE_LIBREADLINE
155/****************************************************************************/
156
157#define HISTORY_FILENAME "freeciv-server_history"
158#define HISTORY_LENGTH 100
159
160static char *history_file = NULL;
161static bool readline_handled_input = FALSE;
162static bool readline_initialized = FALSE;
163
164/*************************************************************************/
167static void handle_readline_input_callback(char *line)
168{
169 if (no_input) {
170 return;
171 }
172
173 if (!line) {
174 handle_stdin_close(); /* maybe print an 'are you sure?' message? */
175 return;
176 }
177
178 if (line[0] != '\0') {
179 add_history(line);
180 }
181
182 con_prompt_enter(); /* just got an 'Enter' hit */
183 current_internal = local_to_internal_string_malloc(line);
184 free(line); /* This is already freed if we exit() with /quit command */
185 handle_stdin_input_free(NULL, current_internal);
186 current_internal = NULL;
187
188 readline_handled_input = TRUE;
189}
190#endif /* FREECIV_HAVE_LIBREADLINE */
191
192/*************************************************************************/
204 void readline_atexit(void)
205{
206#ifdef FREECIV_HAVE_LIBREADLINE
207 if (readline_initialized) {
208 rl_callback_handler_remove();
209 readline_initialized = FALSE;
210 }
211#endif /* FREECIV_HAVE_LIBREADLINE */
212
213 if (current_internal != NULL) {
214 free(current_internal);
215 current_internal = NULL;
216 }
217}
218
219/*************************************************************************/
223 static void close_connection(struct connection *pconn)
224{
225 if (!pconn) {
226 return;
227 }
228
229 if (pconn->server.ping_timers != NULL) {
230 timer_list_destroy(pconn->server.ping_timers);
231 pconn->server.ping_timers = NULL;
232 }
233
234 conn_pattern_list_destroy(pconn->server.ignore_list);
235 pconn->server.ignore_list = NULL;
236
237 /* safe to do these even if not in lists: */
238 conn_list_remove(game.web_client_connections, pconn);
239 conn_list_remove(game.glob_observers, pconn);
240 conn_list_remove(game.all_connections, pconn);
241 conn_list_remove(game.est_connections, pconn);
242
243 pconn->playing = NULL;
244 pconn->client_gui = GUI_STUB;
245 pconn->access_level = ALLOW_NONE;
246 connection_common_close(pconn);
247
248 send_updated_vote_totals(NULL);
249}
250
251/*************************************************************************/
255 void close_connections_and_socket(void)
256{
257 int i;
258
259 lsend_packet_server_shutdown(game.all_connections);
260
261 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
262 if (connections[i].used) {
263 close_connection(&connections[i]);
264 }
265 conn_list_destroy(connections[i].self);
266 }
267
268 /* Remove the game connection lists and make sure they are empty. */
269 conn_list_destroy(game.web_client_connections);
270 conn_list_destroy(game.glob_observers);
271 conn_list_destroy(game.all_connections);
272 conn_list_destroy(game.est_connections);
273
274 for (i = 0; i < listen_count; i++) {
275 fc_closesocket(listen_socks[i]);
276 }
277 FC_FREE(listen_socks);
278
279 if (srvarg.announce != ANNOUNCE_NONE) {
280 fc_closesocket(socklan);
281 }
282
283#ifdef FREECIV_HAVE_LIBREADLINE
284 if (history_file) {
285 write_history(history_file);
286 history_truncate_file(history_file, HISTORY_LENGTH);
287 free(history_file);
288 history_file = NULL;
289 clear_history();
290 }
291#endif /* FREECIV_HAVE_LIBREADLINE */
292
293 send_server_info_to_metaserver(META_GOODBYE);
294 server_close_meta();
295
296 packets_deinit();
297 fc_shutdown_network();
298}
299
300/*************************************************************************/
304 static void really_close_connections(void)
305{
306 struct connection *closing[MAX_NUM_CONNECTIONS];
307 struct connection *pconn;
308 int i, num;
309
310 do {
311 num = 0;
312
313 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
314 pconn = connections + i;
315 if (pconn->used && pconn->server.is_closing) {
316 closing[num++] = pconn;
317 /* Remove closing connections from the lists (hard detach)
318 * to avoid sending to closing connections. */
319 conn_list_remove(game.web_client_connections, pconn);
320 conn_list_remove(game.glob_observers, pconn);
321 conn_list_remove(game.est_connections, pconn);
322 conn_list_remove(game.all_connections, pconn);
323 if (NULL != conn_get_player(pconn)) {
324 conn_list_remove(conn_get_player(pconn)->connections, pconn);
325 }
326 }
327 }
328
329 for (i = 0; i < num; i++) {
330 /* Now really close them. */
331 pconn = closing[i];
332 lost_connection_to_client(pconn);
333 close_connection(pconn);
334 }
335 } while (0 < num); /* May some errors occurred, let's check. */
336}
337
338/*************************************************************************/
342 static void server_conn_close_callback(struct connection *pconn)
343{
344 /* Do as little as possible here to avoid recursive evil. */
345 pconn->server.is_closing = TRUE;
346}
347
348/*************************************************************************/
351 static void cut_lagging_connection(struct connection *pconn)
352{
353 if (!pconn->server.is_closing
354 && game.server.tcptimeout != 0
355 && pconn->last_write
356 && conn_list_size(game.all_connections) > 1
357 && pconn->access_level != ALLOW_HACK
358 && timer_read_seconds(pconn->last_write) > game.server.tcptimeout) {
359 /* Cut the connections to players who lag too much. This
360 * usually happens because client animation slows the client
361 * too much and it can't keep up with the server. We don't
362 * cut HACK connections, or cut in single-player games, since
363 * it wouldn't help the game progress. For other connections
364 * the best thing to do when they lag too much is to be
365 * disconnected and reconnect. */
366 log_verbose("connection (%s) cut due to lagging player",
367 conn_description(pconn));
368 connection_close_server(pconn, _("lagging connection"));
369 }
370}
371
372/*************************************************************************/
376 void flush_packets(void)
377{
378 int i;
379 int max_desc;
380 fd_set writefs, exceptfs;
381 fc_timeval tv;
382 time_t start;
383
384 (void) time(&start);
385
386 for (;;) {
387 /* Can't assign to tv.tv_sec directly on systems where it's unsigned */
388 signed signsecs = (game.server.netwait - (time(NULL) - start));
389
390 if (signsecs < 0) {
391 return;
392 }
393
394 tv.tv_usec = 0;
395 tv.tv_sec = signsecs;
396
397 FC_FD_ZERO(&writefs);
398 FC_FD_ZERO(&exceptfs);
399 max_desc = -1;
400
401 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
402 struct connection *pconn = &connections[i];
403
404 if (pconn->used
405 && !pconn->server.is_closing
406 && 0 < pconn->send_buffer->ndata) {
407 FD_SET(pconn->sock, &writefs);
408 FD_SET(pconn->sock, &exceptfs);
409 max_desc = MAX(pconn->sock, max_desc);
410 }
411 }
412
413 if (max_desc == -1) {
414 return;
415 }
416
417 if (fc_select(max_desc + 1, NULL, &writefs, &exceptfs, &tv) <= 0) {
418 return;
419 }
420
421 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) { /* check for freaky players */
422 struct connection *pconn = &connections[i];
423
424 if (pconn->used && !pconn->server.is_closing) {
425 if (FD_ISSET(pconn->sock, &exceptfs)) {
426 log_verbose("connection (%s) cut due to exception data",
427 conn_description(pconn));
428 connection_close_server(pconn, _("network exception"));
429 } else {
430 if (pconn->send_buffer && pconn->send_buffer->ndata > 0) {
431 if (FD_ISSET(pconn->sock, &writefs)) {
432 flush_connection_send_buffer_all(pconn);
433 } else {
434 cut_lagging_connection(pconn);
435 }
436 }
437 }
438 }
439 }
440 }
441}
442
443 struct packet_to_handle {
444 void *data;
445 enum packet_type type;
446};
447
448/*************************************************************************/
451 static bool get_packet(struct connection *pconn,
452 struct packet_to_handle *ppacket)
453{
454 ppacket->data = get_packet_from_connection(pconn, &ppacket->type);
455
456 return NULL != ppacket->data;
457}
458
459/*************************************************************************/
464 static void incoming_client_packets(struct connection *pconn)
465{
466 struct packet_to_handle packet;
467#if PROCESSING_TIME_STATISTICS
468 struct timer *request_time = NULL;
469#endif
470
471 while (get_packet(pconn, &packet)) {
472 bool command_ok;
473
474#if PROCESSING_TIME_STATISTICS
475 int request_id;
476
477 request_time = timer_renew(request_time, TIMER_USER, TIMER_ACTIVE,
478 request_time != NULL ? NULL : "request");
479 timer_start(request_time);
480#endif /* PROCESSING_TIME_STATISTICS */
481
482 pconn->server.last_request_id_seen
483 = get_next_request_id(pconn->server.last_request_id_seen);
484
485#if PROCESSING_TIME_STATISTICS
486 request_id = pconn->server.last_request_id_seen;
487#endif /* PROCESSING_TIME_STATISTICS */
488
489 connection_do_buffer(pconn);
490 start_processing_request(pconn, pconn->server.last_request_id_seen);
491
492 command_ok = server_packet_input(pconn, packet.data, packet.type);
493 packet_destroy(packet.data, packet.type);
494
495 finish_processing_request(pconn);
496 connection_do_unbuffer(pconn);
497
498#if PROCESSING_TIME_STATISTICS
499 log_verbose("processed request %d in %gms", request_id,
500 timer_read_seconds(request_time) * 1000.0);
501#endif /* PROCESSING_TIME_STATISTICS */
502
503 if (!command_ok) {
504 connection_close_server(pconn, _("rejected"));
505 }
506 }
507
508#if PROCESSING_TIME_STATISTICS
509 timer_destroy(request_time);
510#endif /* PROCESSING_TIME_STATISTICS */
511}
512
513/*************************************************************************/
522 enum server_events server_sniff_all_input(void)
523{
524 int i, s;
525 int max_desc;
526 bool excepting;
527 fd_set readfs, writefs, exceptfs;
528 fc_timeval tv;
529#ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
530 char *bufptr;
531#endif
532
533 con_prompt_init();
534
535#ifdef FREECIV_HAVE_LIBREADLINE
536 {
537 if (!no_input && !readline_initialized) {
538 char *storage_dir = freeciv_storage_dir();
539
540 if (storage_dir != NULL) {
541 int fcdl = strlen(storage_dir) + 1;
542 char *fc_dir = fc_malloc(fcdl);
543
544 if (fc_dir != nullptr) {
545 fc_snprintf(fc_dir, fcdl, "%s", storage_dir);
546
547 if (make_dir(fc_dir, DIRMODE_DEFAULT)) {
548 history_file
549 = fc_malloc(strlen(fc_dir) + 1 + strlen(HISTORY_FILENAME) + 1);
550 if (history_file != nullptr) {
551 strcpy(history_file, fc_dir);
552 strcat(history_file, "/");
553 strcat(history_file, HISTORY_FILENAME);
554 using_history();
555 read_history(history_file);
556 }
557 }
558
559 FC_FREE(fc_dir);
560 }
561 }
562
563 rl_initialize();
564 rl_callback_handler_install((char *) "> ",
565 handle_readline_input_callback);
566 rl_attempted_completion_function = freeciv_completion;
567
568 readline_initialized = TRUE;
569 atexit(readline_atexit);
570 }
571 }
572#endif /* FREECIV_HAVE_LIBREADLINE */
573
574 while (TRUE) {
575 int selret;
576
577 con_prompt_on(); /* accepting new input */
578
579 if (force_end_of_sniff) {
580 force_end_of_sniff = FALSE;
581 con_prompt_off();
582 return S_E_FORCE_END_OF_SNIFF;
583 }
584
585 get_lanserver_announcement();
586
587 /* end server if no players for 'srvarg.quitidle' seconds,
588 * but only if at least one player has previously connected. */
589 if (srvarg.quitidle != 0) {
590 static time_t last_noplayers;
591 static bool conns;
592
593 if (conn_list_size(game.est_connections) > 0) {
594 conns = TRUE;
595 }
596 if (conns && conn_list_size(game.est_connections) == 0) {
597 if (last_noplayers != 0) {
598 if (time(NULL) > last_noplayers + srvarg.quitidle) {
599 save_game_auto("Lost all connections", AS_QUITIDLE);
600
601 if (srvarg.exit_on_end) {
602 log_normal(_("Shutting down for lack of players."));
603 set_meta_message_string("shutting down for lack of players");
604 } else {
605 log_normal(_("Restarting for lack of players."));
606 set_meta_message_string("restarting for lack of players");
607 }
608 (void) send_server_info_to_metaserver(META_INFO);
609
610 set_server_state(S_S_OVER);
611 force_end_of_sniff = TRUE;
612
613 if (srvarg.exit_on_end) {
614 /* No need for anything more; just quit. */
615 server_quit();
616 }
617
618 /* Do not restart before someone has connected and left again */
619 conns = FALSE;
620 }
621 } else {
622 last_noplayers = time(NULL);
623
624 if (srvarg.exit_on_end) {
625 log_normal(_("Shutting down in %d seconds for lack of players."),
626 srvarg.quitidle);
627
628 set_meta_message_string(N_("shutting down soon for lack of players"));
629 } else {
630 log_normal(_("Restarting in %d seconds for lack of players."),
631 srvarg.quitidle);
632
633 set_meta_message_string(N_("restarting soon for lack of players"));
634 }
635 (void) send_server_info_to_metaserver(META_INFO);
636 }
637 } else {
638 last_noplayers = 0;
639 }
640 }
641
642 /* Pinging around for statistics */
643 if (time(NULL) > (game.server.last_ping + game.server.pingtime)) {
644 /* send data about the previous run */
645 send_ping_times_to_all();
646
647 conn_list_iterate(game.all_connections, pconn) {
648 if ((!pconn->server.is_closing
649 && 0 < timer_list_size(pconn->server.ping_timers)
650 && timer_read_seconds(timer_list_front
651 (pconn->server.ping_timers))
652 > game.server.pingtimeout)
653 || pconn->ping_time > game.server.pingtimeout) {
654 /* cut mute players, except for hack-level ones */
655 if (pconn->access_level == ALLOW_HACK) {
656 log_verbose("connection (%s) [hack-level] ping timeout ignored",
657 conn_description(pconn));
658 } else {
659 log_verbose("connection (%s) cut due to ping timeout",
660 conn_description(pconn));
661 connection_close_server(pconn, _("ping timeout"));
662 }
663 } else if (pconn->established) {
664 /* We don't send ping to connection not established, because
665 * we wouldn't be able to handle asynchronous ping/pong with
666 * different packet header size. */
667 connection_ping(pconn);
668 }
669 } conn_list_iterate_end;
670 game.server.last_ping = time(NULL);
671 }
672
673 /* if we've waited long enough after a failure, respond to the client */
674 conn_list_iterate(game.all_connections, pconn) {
675 if (srvarg.auth_enabled
676 && !pconn->server.is_closing
677 && pconn->server.status != AS_ESTABLISHED) {
678 auth_process_status(pconn);
679 }
680 } conn_list_iterate_end
681
682 /* Don't wait if timeout == -1 (i.e. on auto games) */
683 if (S_S_RUNNING == server_state() && game.info.timeout == -1) {
684 call_ai_refresh();
685 script_server_signal_emit("pulse");
686 (void) send_server_info_to_metaserver(META_REFRESH);
687 return S_E_END_OF_TURN_TIMEOUT;
688 }
689
690 tv.tv_sec = 1;
691 tv.tv_usec = 0;
692
693 FC_FD_ZERO(&readfs);
694 FC_FD_ZERO(&writefs);
695 FC_FD_ZERO(&exceptfs);
696
697 if (!no_input) {
698#ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
699 fc_init_console();
700#else /* FREECIV_SOCKET_ZERO_NOT_STDIN */
701# if !defined(__VMS)
702 FD_SET(0, &readfs);
703# endif /* VMS */
704#endif /* FREECIV_SOCKET_ZERO_NOT_STDIN */
705 }
706
707 max_desc = 0;
708 for (i = 0; i < listen_count; i++) {
709 FD_SET(listen_socks[i], &readfs);
710 FD_SET(listen_socks[i], &exceptfs);
711 max_desc = MAX(max_desc, listen_socks[i]);
712 }
713
714 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
715 struct connection *pconn = connections + i;
716
717 if (pconn->used && !pconn->server.is_closing) {
718 FD_SET(pconn->sock, &readfs);
719 if (0 < pconn->send_buffer->ndata) {
720 FD_SET(pconn->sock, &writefs);
721 }
722 FD_SET(pconn->sock, &exceptfs);
723 max_desc = MAX(pconn->sock, max_desc);
724 }
725 }
726 con_prompt_off(); /* output doesn't generate a new prompt */
727
728 selret = fc_select(max_desc + 1, &readfs, &writefs, &exceptfs, &tv);
729 if (selret == 0) {
730 /* timeout */
731 call_ai_refresh();
732 script_server_signal_emit("pulse");
733 (void) send_server_info_to_metaserver(META_REFRESH);
734 if (current_turn_timeout() > 0
735 && S_S_RUNNING == server_state()
736 && game.server.phase_timer
737 && (timer_read_seconds(game.server.phase_timer)
738 + game.server.additional_phase_seconds
739 > game.tinfo.seconds_to_phasedone)) {
740 con_prompt_off();
741
742 return S_E_END_OF_TURN_TIMEOUT;
743 }
744 if ((game.server.autosaves & (1 << AS_TIMER))
745 && S_S_RUNNING == server_state()
746 && (timer_read_seconds(game.server.save_timer)
747 >= game.server.save_frequency * 60)) {
748 save_game_auto("Timer", AS_TIMER);
749 game.server.save_timer = timer_renew(game.server.save_timer,
750 TIMER_USER, TIMER_ACTIVE,
751 game.server.save_timer != NULL
752 ? NULL : "save interval");
753 timer_start(game.server.save_timer);
754 }
755
756 if (!no_input) {
757#if defined(__VMS)
758 {
759 struct {
760 short numchars;
761 char firstchar;
762 char reserved;
763 int reserved2;
764 } ttchar;
765 unsigned long status;
766
767 status = sys$qiow(EFN$C_ENF, tt_chan,
768 IO$_SENSEMODE | IO$M_TYPEAHDCNT, 0, 0, 0,
769 &ttchar, sizeof(ttchar), 0, 0, 0, 0);
770 if (!$VMS_STATUS_SUCCESS(status)) {
771 lib$stop(status);
772 }
773 if (ttchar.numchars) {
774 FD_SET(0, &readfs);
775 } else {
776 continue;
777 }
778 }
779#else /* !__VMS */
780#ifndef FREECIV_SOCKET_ZERO_NOT_STDIN
781 really_close_connections();
782 continue;
783#endif /* FREECIV_SOCKET_ZERO_NOT_STDIN */
784#endif /* !__VMS */
785 }
786 } else if (selret < 0) {
787 log_error("fc_select() failed: %s", fc_strerror(fc_get_errno()));
788 }
789
790 excepting = FALSE;
791 for (i = 0; i < listen_count; i++) {
792 if (FD_ISSET(listen_socks[i], &exceptfs)) {
793 excepting = TRUE;
794 break;
795 }
796 }
797 if (excepting) { /* handle Ctrl-Z suspend/resume */
798 continue;
799 }
800 for (i = 0; i < listen_count; i++) {
801 s = listen_socks[i];
802 if (FD_ISSET(s, &readfs)) { /* new players connects */
803 log_verbose("got new connection");
804 if (-1 == server_accept_connection(s)) {
805 /* There will be a log_error() message from
806 * server_accept_connection() if something
807 * goes wrong, so no need to make another
808 * error-level message here. */
809 log_verbose("failed accepting connection");
810 }
811 }
812 }
813 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
814 /* check for freaky players */
815 struct connection *pconn = &connections[i];
816
817 if (pconn->used
818 && !pconn->server.is_closing
819 && FD_ISSET(pconn->sock, &exceptfs)) {
820 log_verbose("connection (%s) cut due to exception data",
821 conn_description(pconn));
822 connection_close_server(pconn, _("network exception"));
823 }
824 }
825#ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
826 if (!no_input && (bufptr = fc_read_console())) {
827 current_internal = local_to_internal_string_malloc(bufptr);
828
829 con_prompt_enter(); /* Will need a new prompt, regardless */
830 handle_stdin_input_free(NULL, current_internal);
831 current_internal = NULL;
832 }
833#else /* !FREECIV_SOCKET_ZERO_NOT_STDIN */
834 if (!no_input && FD_ISSET(0, &readfs)) { /* input from server operator */
835#ifdef FREECIV_HAVE_LIBREADLINE
836 rl_callback_read_char();
837 if (readline_handled_input) {
838 readline_handled_input = FALSE;
839 con_prompt_enter_clear();
840 }
841 continue;
842#else /* !FREECIV_HAVE_LIBREADLINE */
843 ssize_t didget;
844 char *buffer;
845
846#ifdef HAVE_GETLINE
847 size_t len = 0;
848
849 buffer = NULL; /* Must be NULL when calling getline() */
850 didget = getline(&buffer, &len, stdin);
851 if (didget >= 1) {
852 buffer[--didget] = '\0'; /* Overwrite newline character */
853 log_debug("Got line: \"%s\" (" SIZE_T_PRINTF ", " SIZE_T_PRINTF ")", buffer,
854 didget, len);
855 }
856#else /* HAVE_GETLINE */
857 buffer = malloc(BUF_SIZE + 1);
858
859 didget = read(0, buffer, BUF_SIZE);
860 if (didget > 0) {
861 buffer[didget] = '\0';
862 } else {
863 didget = -1; /* Error or end-of-file: closing stdin... */
864 }
865#endif /* HAVE_GETLINE */
866 if (didget < 0) {
867 handle_stdin_close();
868 }
869
870 con_prompt_enter(); /* Will need a new prompt, regardless */
871
872 if (didget >= 0) {
873 current_internal = local_to_internal_string_malloc(buffer);
874 handle_stdin_input_free(NULL, current_internal);
875 current_internal = NULL;
876 }
877 free(buffer);
878#endif /* !FREECIV_HAVE_LIBREADLINE */
879 } else
880#endif /* !FREECIV_SOCKET_ZERO_NOT_STDIN */
881
882 { /* Input from a player */
883 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
884 struct connection *pconn = connections + i;
885 int nb;
886
887 if (!pconn->used
888 || pconn->server.is_closing
889 || !FD_ISSET(pconn->sock, &readfs)) {
890 continue;
891 }
892
893 nb = read_socket_data(pconn->sock, pconn->buffer);
894 if (0 <= nb) {
895 /* We read packets; now handle them. */
896 incoming_client_packets(pconn);
897 } else if (-2 == nb) {
898 connection_close_server(pconn, _("client disconnected"));
899 } else {
900 /* Read failure; the connection is closed. */
901 connection_close_server(pconn, _("read error"));
902 }
903 }
904
905 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
906 struct connection *pconn = &connections[i];
907
908 if (pconn->used
909 && !pconn->server.is_closing
910 && pconn->send_buffer
911 && pconn->send_buffer->ndata > 0) {
912 if (FD_ISSET(pconn->sock, &writefs)) {
913 flush_connection_send_buffer_all(pconn);
914 } else {
915 cut_lagging_connection(pconn);
916 }
917 }
918 }
919 really_close_connections();
920 break;
921 }
922 }
923 con_prompt_off();
924
925 call_ai_refresh();
926 script_server_signal_emit("pulse");
927
928 if (current_turn_timeout() > 0
929 && S_S_RUNNING == server_state()
930 && game.server.phase_timer
931 && (timer_read_seconds(game.server.phase_timer)
932 + game.server.additional_phase_seconds
933 > game.tinfo.seconds_to_phasedone)) {
934 return S_E_END_OF_TURN_TIMEOUT;
935 }
936 if ((game.server.autosaves & (1 << AS_TIMER))
937 && S_S_RUNNING == server_state()
938 && (timer_read_seconds(game.server.save_timer)
939 >= game.server.save_frequency * 60)) {
940 save_game_auto("Timer", AS_TIMER);
941 game.server.save_timer = timer_renew(game.server.save_timer,
942 TIMER_USER, TIMER_ACTIVE,
943 game.server.save_timer != NULL
944 ? NULL : "save interval");
945 timer_start(game.server.save_timer);
946 }
947
948 return S_E_OTHERWISE;
949}
950
951/*************************************************************************/
959 static const char *makeup_connection_name(int *id)
960{
961 static unsigned short i = 0;
962 static char name[MAX_LEN_NAME];
963
964 for (;;) {
965 if (i == (unsigned short) - 1) {
966 /* don't use 0 */
967 i++;
968 }
969 fc_snprintf(name, sizeof(name), "c%u", (unsigned int)++i);
970 if (NULL == player_by_name(name)
971 && NULL == player_by_user(name)
972 && NULL == conn_by_number(i)
973 && NULL == conn_by_user(name)) {
974 *id = i;
975 return name;
976 }
977 }
978}
979
980/*************************************************************************/
986 static int server_accept_connection(int sockfd)
987{
988 /* This used to have size_t for some platforms. If this is necessary
989 * it should be done with a configure check not a platform check. */
990 socklen_t fromlen;
991
992 int new_sock;
993 union fc_sockaddr fromend;
994 bool nameinfo = FALSE;
995#ifdef FREECIV_IPV6_SUPPORT
996 char host[NI_MAXHOST], service[NI_MAXSERV];
997 char dst[INET6_ADDRSTRLEN];
998#else /* IPv6 support */
999 struct hostent *from;
1000 const char *host = NULL;
1001 const char *dst;
1002#endif /* IPv6 support */
1003
1004 fromlen = sizeof(fromend);
1005
1006 if ((new_sock = accept(sockfd, &fromend.saddr, &fromlen)) == -1) {
1007 log_error("accept failed: %s", fc_strerror(fc_get_errno()));
1008 return -1;
1009 }
1010
1011#ifdef FREECIV_IPV6_SUPPORT
1012 if (fromend.saddr.sa_family == AF_INET6) {
1013 inet_ntop(AF_INET6, &fromend.saddr_in6.sin6_addr,
1014 dst, sizeof(dst));
1015 } else if (fromend.saddr.sa_family == AF_INET) {
1016 inet_ntop(AF_INET, &fromend.saddr_in4.sin_addr, dst, sizeof(dst));
1017 } else {
1018 fc_assert(FALSE);
1019
1020 log_error("Unsupported address family in server_accept_connection()");
1021
1022 return -1;
1023 }
1024#else /* IPv6 support */
1025 dst = inet_ntoa(fromend.saddr_in4.sin_addr);
1026#endif /* IPv6 support */
1027
1028 if (0 != game.server.maxconnectionsperhost) {
1029 int count = 0;
1030
1031 conn_list_iterate(game.all_connections, pconn) {
1032 if (0 != strcmp(dst, pconn->server.ipaddr)) {
1033 continue;
1034 }
1035 if (++count >= game.server.maxconnectionsperhost) {
1036 log_verbose("Rejecting new connection from %s: maximum number of "
1037 "connections for this address exceeded (%d).",
1038 dst, game.server.maxconnectionsperhost);
1039
1040 /* Disconnect the accepted socket. */
1041 fc_closesocket(new_sock);
1042
1043 return -1;
1044 }
1045 } conn_list_iterate_end;
1046 }
1047
1048#ifdef FREECIV_IPV6_SUPPORT
1049 nameinfo = (0 == getnameinfo(&fromend.saddr, fromlen, host, NI_MAXHOST,
1050 service, NI_MAXSERV, NI_NUMERICSERV)
1051 && '\0' != host[0]);
1052#else /* IPv6 support */
1053 from = gethostbyaddr((char *) &fromend.saddr_in4.sin_addr,
1054 sizeof(fromend.saddr_in4.sin_addr), AF_INET);
1055 if (NULL != from && '\0' != from->h_name[0]) {
1056 host = from->h_name;
1057 nameinfo = TRUE;
1058 }
1059#endif /* IPv6 support */
1060
1061 return server_make_connection(new_sock,
1062 (nameinfo ? host : dst), dst);
1063}
1064
1065/*************************************************************************/
1071 int server_make_connection(int new_sock, const char *client_addr,
1072 const char *client_ip)
1073{
1074 struct timer *timer;
1075 int i;
1076
1077 fc_nonblock(new_sock);
1078
1079 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
1080 struct connection *pconn = &connections[i];
1081
1082 if (!pconn->used) {
1083 connection_common_init(pconn);
1084 pconn->sock = new_sock;
1085 pconn->observer = FALSE;
1086 pconn->playing = NULL;
1087 pconn->capability[0] = '\0';
1088 pconn->access_level = access_level_for_next_connection();
1089 pconn->notify_of_writable_data = NULL;
1090 pconn->server.currently_processed_request_id = 0;
1091 pconn->server.last_request_id_seen = 0;
1092 pconn->server.auth_tries = 0;
1093 pconn->server.auth_settime = 0;
1094 pconn->server.status = AS_NOT_ESTABLISHED;
1095 pconn->server.ping_timers = timer_list_new_full(timer_destroy);
1096 pconn->server.granted_access_level = pconn->access_level;
1097 pconn->server.ignore_list =
1098 conn_pattern_list_new_full(conn_pattern_destroy);
1099 pconn->server.is_closing = FALSE;
1100 pconn->ping_time = -1.0;
1101 pconn->incoming_packet_notify = NULL;
1102 pconn->outgoing_packet_notify = NULL;
1103
1104 sz_strlcpy(pconn->username, makeup_connection_name(&pconn->id));
1105 sz_strlcpy(pconn->addr, client_addr);
1106 sz_strlcpy(pconn->server.ipaddr, client_ip);
1107
1108 conn_list_append(game.all_connections, pconn);
1109
1110 log_verbose("connection (%s) from %s (%s)",
1111 pconn->username, pconn->addr, pconn->server.ipaddr);
1112 /* Give a ping timeout to send the PACKET_SERVER_JOIN_REQ, or close
1113 * the mute connection. This timer will be canceled into
1114 * connecthand.c:handle_login_request(). */
1115 timer = timer_new(TIMER_USER, TIMER_ACTIVE, "ping timer");
1116 timer_start(timer);
1117 timer_list_append(pconn->server.ping_timers, timer);
1118
1119 return 0;
1120 }
1121 }
1122
1123 log_error("maximum number of connections reached");
1124 fc_closesocket(new_sock);
1125
1126 return -1;
1127}
1128
1129/*************************************************************************/
1133 int server_open_socket(void)
1134{
1135 /* setup socket address */
1136 union fc_sockaddr addr;
1137#ifdef HAVE_IP_MREQN
1138 struct ip_mreqn mreq4;
1139#else
1140 struct ip_mreq mreq4;
1141#endif
1142 const char *cause, *group;
1143 int j, on, s;
1144 int lan_family;
1145 struct fc_sockaddr_list *list;
1146 int name_count;
1147 fc_errno eno = 0;
1148 union fc_sockaddr *problematic = NULL;
1149
1150#ifdef FREECIV_IPV6_SUPPORT
1151 struct ipv6_mreq mreq6;
1152#endif
1153
1154 log_verbose("Server attempting to listen on %s:%d",
1155 srvarg.bind_addr ? srvarg.bind_addr : "(any)",
1156 srvarg.port);
1157
1158 /* Any supported family will do */
1159 list = net_lookup_service(srvarg.bind_addr, srvarg.port, FC_ADDR_ANY);
1160
1161 name_count = fc_sockaddr_list_size(list);
1162
1163 /* Lookup addresses to bind. */
1164 if (name_count <= 0) {
1165 log_fatal(_("Server: bad address: <%s:%d>."),
1166 srvarg.bind_addr ? srvarg.bind_addr : "(none)", srvarg.port);
1167 exit(EXIT_FAILURE);
1168 }
1169
1170 cause = "internal"; /* If cause is not overwritten but gets printed... */
1171 on = 1;
1172
1173 /* Loop to create sockets, bind, listen. */
1174 listen_socks = fc_calloc(name_count, sizeof(listen_socks[0]));
1175 listen_count = 0;
1176
1177 fc_sockaddr_list_iterate(list, paddr) {
1178 /* Create socket for client connections. */
1179 s = socket(paddr->saddr.sa_family, SOCK_STREAM, 0);
1180 if (s == -1) {
1181 /* Probably EAFNOSUPPORT or EPROTONOSUPPORT.
1182 * Kernel might have disabled AF_INET6. */
1183 eno = fc_get_errno();
1184 cause = "socket";
1185 problematic = paddr;
1186 continue;
1187 }
1188
1189#ifndef FREECIV_HAVE_WINSOCK
1190 /* SO_REUSEADDR considered harmful on Win, necessary otherwise */
1191 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1192 (char *)&on, sizeof(on)) == -1) {
1193 log_error("setsockopt SO_REUSEADDR failed: %s",
1194 fc_strerror(fc_get_errno()));
1195 sockaddr_debug(paddr, LOG_NORMAL);
1196 }
1197#endif /* FREECIV_HAVE_WINSOCK */
1198
1199 /* AF_INET6 sockets should use IPv6 only,
1200 * without stealing IPv4 from AF_INET sockets. */
1201#ifdef FREECIV_IPV6_SUPPORT
1202 if (paddr->saddr.sa_family == AF_INET6) {
1203#ifdef IPV6_V6ONLY
1204 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
1205 (char *)&on, sizeof(on)) == -1) {
1206 log_error("setsockopt IPV6_V6ONLY failed: %s",
1207 fc_strerror(fc_get_errno()));
1208 sockaddr_debug(paddr, LOG_DEBUG);
1209 }
1210#endif /* IPV6_V6ONLY */
1211 }
1212#endif /* IPv6 support */
1213
1214 if (bind(s, &paddr->saddr, sockaddr_size(paddr)) == -1) {
1215 eno = fc_get_errno();
1216 cause = "bind";
1217 problematic = paddr;
1218
1219 if (eno == EADDRNOTAVAIL) {
1220 /* Close only this socket. This address is not available.
1221 * This can happen with the IPv6 wildcard address if this
1222 * machine has no IPv6 interfaces. */
1223 /* If you change this logic, be sure to make clientside checking
1224 * of acceptable port to match. */
1225 fc_closesocket(s);
1226 continue;
1227 } else {
1228 /* Close all sockets. Another program might have bound to
1229 * one of our addresses, and might hijack some of our
1230 * connections. */
1231 fc_closesocket(s);
1232 for (j = 0; j < listen_count; j++) {
1233 fc_closesocket(listen_socks[j]);
1234 }
1235 listen_count = 0;
1236 break;
1237 }
1238 }
1239
1240 if (listen(s, MAX_NUM_CONNECTIONS) == -1) {
1241 eno = fc_get_errno();
1242 cause = "listen";
1243 problematic = paddr;
1244 fc_closesocket(s);
1245 continue;
1246 }
1247
1248 listen_socks[listen_count++] = s;
1249 } fc_sockaddr_list_iterate_end;
1250
1251 if (listen_count == 0) {
1252 log_fatal("%s failure: %s (%d failed)", cause, fc_strerror(eno), name_count);
1253 if (problematic != NULL) {
1254 sockaddr_debug(problematic, LOG_NORMAL);
1255 }
1256 fc_sockaddr_list_iterate(list, paddr) {
1257 /* Do not list already logged 'problematic' again */
1258 if (paddr != problematic) {
1259 sockaddr_debug(paddr, LOG_DEBUG);
1260 }
1261 } fc_sockaddr_list_iterate_end;
1262 exit(EXIT_FAILURE);
1263 }
1264
1265 fc_sockaddr_list_destroy(list);
1266
1267 connections_set_close_callback(server_conn_close_callback);
1268
1269 if (srvarg.announce == ANNOUNCE_NONE) {
1270 return 0;
1271 }
1272
1273#ifdef FREECIV_IPV6_SUPPORT
1274 if (srvarg.announce == ANNOUNCE_IPV6) {
1275 lan_family = AF_INET6;
1276 } else
1277#endif /* IPV6 support */
1278 {
1279 lan_family = AF_INET;
1280 }
1281
1282 /* Create socket for server LAN announcements */
1283 if ((socklan = socket(lan_family, SOCK_DGRAM, 0)) < 0) {
1284 log_error("Announcement socket failed: %s", fc_strerror(fc_get_errno()));
1285 return 0; /* FIXME: Should this cause hard error as exit(EXIT_FAILURE).
1286 * It's a failure to do as commandline parameters requested
1287 * after all */
1288 }
1289
1290 if (setsockopt(socklan, SOL_SOCKET, SO_REUSEADDR,
1291 (char *)&on, sizeof(on)) == -1) {
1292 log_error("SO_REUSEADDR failed: %s", fc_strerror(fc_get_errno()));
1293 }
1294
1295 fc_nonblock(socklan);
1296
1297 group = get_multicast_group(srvarg.announce == ANNOUNCE_IPV6);
1298
1299 memset(&addr, 0, sizeof(addr));
1300
1301 addr.saddr.sa_family = lan_family;
1302
1303#ifdef FREECIV_IPV6_SUPPORT
1304 if (addr.saddr.sa_family == AF_INET6) {
1305 addr.saddr_in6.sin6_family = AF_INET6;
1306 addr.saddr_in6.sin6_port = htons(SERVER_LAN_PORT);
1307 addr.saddr_in6.sin6_addr = in6addr_any;
1308 } else
1309#endif /* IPv6 support */
1310 if (addr.saddr.sa_family == AF_INET) {
1311 addr.saddr_in4.sin_family = AF_INET;
1312 addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT);
1313 addr.saddr_in4.sin_addr.s_addr = htonl(INADDR_ANY);
1314 } else {
1315 fc_assert(FALSE);
1316
1317 log_error("Unsupported address family in server_open_socket()");
1318 }
1319
1320 if (bind(socklan, &addr.saddr, sockaddr_size(&addr)) < 0) {
1321 log_error("Announcement socket binding failed: %s", fc_strerror(fc_get_errno()));
1322 }
1323
1324#ifdef FREECIV_IPV6_SUPPORT
1325 if (addr.saddr.sa_family == AF_INET6) {
1326 inet_pton(AF_INET6, group, &mreq6.ipv6mr_multiaddr.s6_addr);
1327 mreq6.ipv6mr_interface = 0; /* TODO: Interface selection */
1328 if (setsockopt(socklan, IPPROTO_IPV6, FC_IPV6_ADD_MEMBERSHIP,
1329 (const char*)&mreq6, sizeof(mreq6)) < 0) {
1330 log_error("FC_IPV6_ADD_MEMBERSHIP (%s) failed: %s",
1331 group, fc_strerror(fc_get_errno()));
1332 }
1333 } else
1334#endif /* IPV6 Support */
1335 if (addr.saddr.sa_family == AF_INET) {
1336 fc_inet_aton(group, &mreq4.imr_multiaddr, FALSE);
1337#ifdef HAVE_IP_MREQN
1338 mreq4.imr_address.s_addr = htonl(INADDR_ANY);
1339 mreq4.imr_ifindex = 0;
1340#else
1341 mreq4.imr_interface.s_addr = htonl(INADDR_ANY);
1342#endif
1343
1344 if (setsockopt(socklan, IPPROTO_IP, IP_ADD_MEMBERSHIP,
1345 (const char*)&mreq4, sizeof(mreq4)) < 0) {
1346 log_error("IP_ADD_MEMBERSHIP (%s) failed: %s",
1347 group, fc_strerror(fc_get_errno()));
1348 }
1349 } else {
1350 fc_assert(FALSE);
1351
1352 log_error("Unsupported address family for broadcasting.");
1353 }
1354
1355 return 0;
1356}
1357
1358/*************************************************************************/
1362 void init_connections(void)
1363{
1364 int i;
1365
1366 game.all_connections = conn_list_new();
1367 game.est_connections = conn_list_new();
1368 game.glob_observers = conn_list_new();
1369 game.web_client_connections = conn_list_new();
1370
1371 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
1372 struct connection *pconn = &connections[i];
1373
1374 pconn->used = FALSE;
1375 pconn->self = conn_list_new();
1376 conn_list_prepend(pconn->self, pconn);
1377 }
1378#if defined(__VMS)
1379 {
1380 unsigned long status;
1381
1382 $DESCRIPTOR (tt_desc, "SYS$INPUT");
1383 status = sys$assign(&tt_desc, &tt_chan, 0, 0);
1384 if (!$VMS_STATUS_SUCCESS(status)) {
1385 lib$stop(status);
1386 }
1387 }
1388#endif /* VMS */
1389}
1390
1391/*************************************************************************/
1394 static void start_processing_request(struct connection *pconn,
1395 int request_id)
1396{
1397 fc_assert_ret(request_id);
1398 fc_assert_ret(pconn->server.currently_processed_request_id == 0);
1399 log_debug("start processing packet %d from connection %d",
1400 request_id, pconn->id);
1401 conn_compression_freeze(pconn);
1402 send_packet_processing_started(pconn);
1403 pconn->server.currently_processed_request_id = request_id;
1404}
1405
1406/*************************************************************************/
1409 static void finish_processing_request(struct connection *pconn)
1410{
1411 if (!pconn || !pconn->used) {
1412 return;
1413 }
1414
1415 fc_assert_ret(pconn->server.currently_processed_request_id);
1416
1417 log_debug("finish processing packet %d from connection %d",
1418 pconn->server.currently_processed_request_id, pconn->id);
1419 send_packet_processing_finished(pconn);
1420 pconn->server.currently_processed_request_id = 0;
1421 conn_compression_thaw(pconn);
1422}
1423
1424/*************************************************************************/
1427 static void connection_ping(struct connection *pconn)
1428{
1429 struct timer *timer = timer_new(TIMER_USER, TIMER_ACTIVE, "connection ping");
1430
1431 log_debug("sending ping to %s (open=%d)", conn_description(pconn),
1432 timer_list_size(pconn->server.ping_timers));
1433 timer_start(timer);
1434 timer_list_append(pconn->server.ping_timers, timer);
1435 send_packet_conn_ping(pconn);
1436}
1437
1438/*************************************************************************/
1441 void handle_conn_pong(struct connection *pconn)
1442{
1443 struct timer *timer;
1444
1445 if (timer_list_size(pconn->server.ping_timers) == 0) {
1446 log_error("got unexpected pong from %s", conn_description(pconn));
1447 return;
1448 }
1449
1450 timer = timer_list_front(pconn->server.ping_timers);
1451 pconn->ping_time = timer_read_seconds(timer);
1452 timer_list_pop_front(pconn->server.ping_timers);
1453 log_debug("got pong from %s (open=%d); ping time = %fs",
1454 conn_description(pconn),
1455 timer_list_size(pconn->server.ping_timers), pconn->ping_time);
1456}
1457
1458/*************************************************************************/
1461 void handle_client_heartbeat(struct connection *pconn)
1462{
1463 log_debug("Received heartbeat");
1464}
1465
1466/*************************************************************************/
1469 static void send_ping_times_to_all(void)
1470{
1471 struct packet_conn_ping_info packet;
1472 int i;
1473
1474 i = 0;
1475 conn_list_iterate(game.est_connections, pconn) {
1476 if (!pconn->used) {
1477 continue;
1478 }
1479 fc_assert(i < ARRAY_SIZE(packet.conn_id));
1480 packet.conn_id[i] = pconn->id;
1481 packet.ping_time[i] = pconn->ping_time;
1482 i++;
1483 } conn_list_iterate_end;
1484 packet.connections = i;
1485
1486 lsend_packet_conn_ping_info(game.est_connections, &packet);
1487}
1488
1489/*************************************************************************/
1493 static void get_lanserver_announcement(void)
1494{
1495 fd_set readfs, exceptfs;
1496 fc_timeval tv;
1497 char msgbuf[128];
1498 struct data_in din;
1499 int type;
1500
1501 if (srvarg.announce == ANNOUNCE_NONE) {
1502 return;
1503 }
1504
1505 FD_ZERO(&readfs);
1506 FD_ZERO(&exceptfs);
1507 FD_SET(socklan, &exceptfs);
1508 FD_SET(socklan, &readfs);
1509
1510 tv.tv_sec = 0;
1511 tv.tv_usec = 0;
1512
1513 while (fc_select(socklan + 1, &readfs, NULL, &exceptfs, &tv) == -1) {
1514 if (errno != EINTR) {
1515 log_error("select failed: %s", fc_strerror(fc_get_errno()));
1516 return;
1517 }
1518 /* EINTR can happen sometimes, especially when compiling with -pg.
1519 * Generally we just want to run select again. */
1520 }
1521
1522 /* We would need a raw network connection for broadcast messages */
1523 if (FD_ISSET(socklan, &readfs)) {
1524 if (0 < recvfrom(socklan, msgbuf, sizeof(msgbuf), 0, NULL, NULL)) {
1525 dio_input_init(&din, msgbuf, 1);
1526 dio_get_uint8_raw(&din, &type);
1527 if (type == SERVER_LAN_VERSION) {
1528 log_debug("Received request for server LAN announcement.");
1529 send_lanserver_response();
1530 } else {
1531 log_debug("Received invalid request for server LAN announcement.");
1532 }
1533 }
1534 }
1535}
1536
1537/*************************************************************************/
1541/* We would need a raw network connection for broadcast messages */
1542 static void send_lanserver_response(void)
1543{
1544#ifndef FREECIV_HAVE_WINSOCK
1545 unsigned char buffer[MAX_LEN_PACKET];
1546#else /* FREECIV_HAVE_WINSOCK */
1547 char buffer[MAX_LEN_PACKET];
1548#endif /* FREECIV_HAVE_WINSOCK */
1549 char hostname[512];
1550 char port[256];
1551 char version[256];
1552 char players[256];
1553 int nhumans;
1554 char humans[256];
1555 char status[256];
1556 struct raw_data_out dout;
1557 union fc_sockaddr addr;
1558 int socksend, setting = 1;
1559 const char *group;
1560 size_t size;
1561#ifndef FREECIV_HAVE_WINSOCK
1562 unsigned char ttl;
1563#endif
1564 int addr_fam = addr_family_for_announce_type(srvarg.announce);
1565
1566 /* Create a socket to broadcast to client. */
1567 if ((socksend = socket(addr_fam, SOCK_DGRAM, 0)) < 0) {
1568 log_error("Lan response socket failed: %s", fc_strerror(fc_get_errno()));
1569 return;
1570 }
1571
1572 /* Set the UDP Multicast group IP address of the packet. */
1573 group = get_multicast_group(srvarg.announce == ANNOUNCE_IPV6);
1574 memset(&addr, 0, sizeof(addr));
1575#ifdef FREECIV_IPV6_SUPPORT
1576 if (addr_fam == AF_INET6) {
1577 addr.saddr_in6.sin6_family = AF_INET6;
1578 addr.saddr_in6.sin6_port = htons(SERVER_LAN_PORT + 1);
1579 inet_pton(addr_fam, group, &addr.saddr_in6.sin6_addr);
1580 } else
1581#endif /* FREECIV_IPV6_SUPPORT */
1582 {
1583 addr.saddr_in4.sin_family = AF_INET;
1584 addr.saddr_in4.sin_addr.s_addr = inet_addr(group);
1585 addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT + 1);
1586 }
1587
1588 /* This setsockopt call fails on Windows 98, so we stick with the default
1589 * value of 1 on Windows, which should be fine in most cases */
1590#ifndef FREECIV_HAVE_WINSOCK
1591 {
1592 int proto;
1593
1594#ifdef FREECIV_IPV6_SUPPORT
1595 if (addr_fam == AF_INET6) {
1596 proto = IPPROTO_IPV6;
1597 } else
1598#endif /* FREECIV_IPV6_SUPPORT */
1599 {
1600 proto = IPPROTO_IP;
1601 }
1602
1603 /* Set the Time-to-Live field for the packet. */
1604 ttl = SERVER_LAN_TTL;
1605 if (setsockopt(socksend, proto, IP_MULTICAST_TTL,
1606 (const char*)&ttl, sizeof(ttl))) {
1607 log_error("setsockopt failed: %s", fc_strerror(fc_get_errno()));
1608 return;
1609 }
1610 }
1611#endif /* FREECIV_HAVE_WINSOCK */
1612
1613 if (setsockopt(socksend, SOL_SOCKET, SO_BROADCAST,
1614 (const char*)&setting, sizeof(setting))) {
1615 log_error("Lan response setsockopt failed: %s", fc_strerror(fc_get_errno()));
1616 return;
1617 }
1618
1619 /* Create a description of server state to send to clients. */
1620 if (srvarg.identity_name[0] != '\0') {
1621 sz_strlcpy(hostname, srvarg.identity_name);
1622 } else if (fc_gethostname(hostname, sizeof(hostname)) != 0) {
1623 sz_strlcpy(hostname, "none");
1624 }
1625
1626 fc_snprintf(version, sizeof(version), "%d.%d.%d%s",
1627 MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, VERSION_LABEL);
1628
1629 switch (server_state()) {
1630 case S_S_INITIAL:
1631 /* TRANS: Game state for local server */
1632 fc_snprintf(status, sizeof(status), _("Pregame"));
1633 break;
1634 case S_S_RUNNING:
1635 /* TRANS: Game state for local server */
1636 fc_snprintf(status, sizeof(status), _("Running"));
1637 break;
1638 case S_S_OVER:
1639 /* TRANS: Game state for local server */
1640 fc_snprintf(status, sizeof(status), _("Game over"));
1641 break;
1642 }
1643
1644 fc_snprintf(players, sizeof(players), "%d",
1645 normal_player_count());
1646
1647 nhumans = 0;
1648 players_iterate(pplayer) {
1649 if (pplayer->is_alive && is_human(pplayer)) {
1650 nhumans++;
1651 }
1652 } players_iterate_end;
1653 fc_snprintf(humans, sizeof(humans), "%d", nhumans);
1654
1655 fc_snprintf(port, sizeof(port), "%d",
1656 srvarg.port);
1657
1658 dio_output_init(&dout, buffer, sizeof(buffer));
1659 dio_put_uint8_raw(&dout, SERVER_LAN_VERSION);
1660 dio_put_string_raw(&dout, hostname);
1661 dio_put_string_raw(&dout, port);
1662 dio_put_string_raw(&dout, version);
1663 dio_put_string_raw(&dout, status);
1664 dio_put_string_raw(&dout, players);
1665 dio_put_string_raw(&dout, humans);
1666 dio_put_string_raw(&dout, get_meta_message_string());
1667 size = dio_output_used(&dout);
1668
1669 /* Sending packet to client with the information gathered above. */
1670 if (sendto(socksend, buffer, size, 0, &addr.saddr,
1671 sockaddr_size(&addr)) < 0) {
1672 log_error("landserver response sendto failed: %s",
1673 fc_strerror(fc_get_errno()));
1674 return;
1675 }
1676
1677 fc_closesocket(socksend);
1678}
call_ai_refresh
void call_ai_refresh(void)
Definition aiiface.c:254
aiiface.h
auth_process_status
void auth_process_status(struct connection *pconn)
Definition auth.c:207
auth.h
capability.h
self
static struct ai_type * self
Definition classicai.c:46
list
static struct fc_sockaddr_list * list
Definition clinet.c:102
incite_cost
char * incite_cost
Definition comments.c:74
MAX_LEN_PACKET
#define MAX_LEN_PACKET
Definition conn_types.h:29
lost_connection_to_client
void lost_connection_to_client(struct connection *pconn)
Definition connecthand.c:530
connection_close_server
void connection_close_server(struct connection *pconn, const char *reason)
Definition connecthand.c:1007
connecthand.h
conn_get_player
struct player * conn_get_player(const struct connection *pconn)
Definition connection.c:763
conn_by_user
struct connection * conn_by_user(const char *user_name)
Definition connection.c:377
connections_set_close_callback
void connections_set_close_callback(conn_close_fn_t func)
Definition connection.c:80
flush_connection_send_buffer_all
void flush_connection_send_buffer_all(struct connection *pc)
Definition connection.c:230
get_next_request_id
int get_next_request_id(int old_request_id)
Definition connection.c:530
connection_do_buffer
void connection_do_buffer(struct connection *pc)
Definition connection.c:324
conn_pattern_destroy
void conn_pattern_destroy(struct conn_pattern *ppattern)
Definition connection.c:809
connection_common_init
void connection_common_init(struct connection *pconn)
Definition connection.c:603
conn_description
const char * conn_description(const struct connection *pconn)
Definition connection.c:474
connection_common_close
void connection_common_close(struct connection *pconn)
Definition connection.c:630
conn_compression_freeze
void conn_compression_freeze(struct connection *pconn)
Definition connection.c:694
conn_by_number
struct connection * conn_by_number(int id)
Definition connection.c:421
read_socket_data
int read_socket_data(int sock, struct socket_packet_buffer *buffer)
Definition connection.c:129
connection_do_unbuffer
void connection_do_unbuffer(struct connection *pc)
Definition connection.c:336
AS_NOT_ESTABLISHED
@ AS_NOT_ESTABLISHED
Definition connection.h:93
AS_ESTABLISHED
@ AS_ESTABLISHED
Definition connection.h:97
conn_compression_thaw
bool conn_compression_thaw(struct connection *pconn)
Definition packets.c:194
conn_list_iterate
#define conn_list_iterate(connlist, pconn)
Definition connection.h:108
conn_list_iterate_end
#define conn_list_iterate_end
Definition connection.h:110
con_prompt_enter_clear
void con_prompt_enter_clear(void)
Definition console.c:314
con_prompt_init
void con_prompt_init(void)
Definition console.c:272
con_prompt_enter
void con_prompt_enter(void)
Definition console.c:303
con_prompt_off
void con_prompt_off(void)
Definition console.c:295
con_prompt_on
void con_prompt_on(void)
Definition console.c:286
console.h
dataio.h
dio_put_uint8_raw
int dio_put_uint8_raw(struct raw_data_out *dout, int value)
Definition dataio_raw.c:265
dio_output_init
void dio_output_init(struct raw_data_out *dout, void *destination, size_t dest_size)
Definition dataio_raw.c:171
dio_put_string_raw
int dio_put_string_raw(struct raw_data_out *dout, const char *value)
Definition dataio_raw.c:512
dio_get_uint8_raw
bool dio_get_uint8_raw(struct data_in *din, int *dest)
Definition dataio_raw.c:598
dio_output_used
size_t dio_output_used(struct raw_data_out *dout)
Definition dataio_raw.c:184
dio_input_init
void dio_input_init(struct data_in *din, const void *src, size_t src_size)
Definition dataio_raw.c:202
events.h
fc_prehdrs.h
MAX_NUM_CONNECTIONS
#define MAX_NUM_CONNECTIONS
Definition fc_types.h:38
MAX_LEN_NAME
#define MAX_LEN_NAME
Definition fc_types.h:66
fciconv.h
local_to_internal_string_malloc
char * local_to_internal_string_malloc(const char *text)
fcintl.h
_
#define _(String)
Definition fcintl.h:67
N_
#define N_(String)
Definition fcintl.h:69
game
struct civ_game game
Definition game.c:62
current_turn_timeout
int current_turn_timeout(void)
Definition game.c:854
game.h
AS_QUITIDLE
@ AS_QUITIDLE
Definition game.h:62
AS_TIMER
@ AS_TIMER
Definition game.h:64
type
GType type
Definition repodlgs.c:1313
name
const char * name
Definition inputfile.c:127
log.h
fc_assert_ret
#define fc_assert_ret(condition)
Definition log.h:191
log_verbose
#define log_verbose(message,...)
Definition log.h:109
fc_assert
#define fc_assert(condition)
Definition log.h:176
log_fatal
#define log_fatal(message,...)
Definition log.h:100
log_debug
#define log_debug(message,...)
Definition log.h:115
log_normal
#define log_normal(message,...)
Definition log.h:107
LOG_DEBUG
@ LOG_DEBUG
Definition log.h:34
LOG_NORMAL
@ LOG_NORMAL
Definition log.h:32
log_error
#define log_error(message,...)
Definition log.h:103
mem.h
fc_calloc
#define fc_calloc(n, esz)
Definition mem.h:38
FC_FREE
#define FC_FREE(ptr)
Definition mem.h:41
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
set_meta_message_string
void set_meta_message_string(const char *string)
Definition meta.c:180
server_close_meta
void server_close_meta(void)
Definition meta.c:455
get_meta_message_string
const char * get_meta_message_string(void)
Definition meta.c:115
send_server_info_to_metaserver
bool send_server_info_to_metaserver(enum meta_flag flag)
Definition meta.c:491
meta.h
META_GOODBYE
@ META_GOODBYE
Definition meta.h:28
META_INFO
@ META_INFO
Definition meta.h:26
META_REFRESH
@ META_REFRESH
Definition meta.h:27
fc_shutdown_network
void fc_shutdown_network(void)
Definition netintf.c:217
ANNOUNCE_IPV6
@ ANNOUNCE_IPV6
Definition net_types.h:56
ANNOUNCE_NONE
@ ANNOUNCE_NONE
Definition net_types.h:54
addr_family_for_announce_type
int addr_family_for_announce_type(enum announce_type announce)
Definition netintf.c:685
FC_ADDR_ANY
@ FC_ADDR_ANY
Definition net_types.h:64
fc_inet_aton
bool fc_inet_aton(const char *cp, struct in_addr *inp, bool addr_none_ok)
Definition netintf.c:466
net_lookup_service
struct fc_sockaddr_list * net_lookup_service(const char *name, int port, enum fc_addr_family family)
Definition netintf.c:411
fc_closesocket
void fc_closesocket(int sock)
Definition netintf.c:186
sockaddr_debug
void sockaddr_debug(union fc_sockaddr *addr, enum log_level lvl)
Definition netintf.c:269
sockaddr_size
int sockaddr_size(union fc_sockaddr *addr)
Definition netintf.c:305
fc_nonblock
void fc_nonblock(int sockfd)
Definition netintf.c:227
fc_select
int fc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, fc_timeval *timeout)
Definition netintf.c:125
netintf.h
fc_timeval
struct timeval fc_timeval
Definition netintf.h:90
fc_sockaddr_list_iterate_end
#define fc_sockaddr_list_iterate_end
Definition netintf.h:85
FC_FD_ZERO
#define FC_FD_ZERO(p)
Definition netintf.h:57
socklen_t
int socklen_t
Definition netintf.h:67
fc_sockaddr_list_iterate
#define fc_sockaddr_list_iterate(sockaddrlist, paddr)
Definition netintf.h:83
FC_IPV6_ADD_MEMBERSHIP
#define FC_IPV6_ADD_MEMBERSHIP
Definition netintf.h:63
packets_deinit
void packets_deinit(void)
Definition packets.c:900
packets.h
get_packet_from_connection
#define get_packet_from_connection(pc, ptype)
Definition packets.h:90
packet_destroy
void packet_destroy(void *packet, enum packet_type type)
Definition packets_gen.c:91173
send_packet_conn_ping
int send_packet_conn_ping(struct connection *pc)
Definition packets_gen.c:39081
send_packet_processing_finished
int send_packet_processing_finished(struct connection *pc)
Definition packets_gen.c:1162
send_packet_processing_started
int send_packet_processing_started(struct connection *pc)
Definition packets_gen.c:1122
lsend_packet_conn_ping_info
void lsend_packet_conn_ping_info(struct conn_list *dest, const struct packet_conn_ping_info *packet)
Definition packets_gen.c:39046
lsend_packet_server_shutdown
void lsend_packet_server_shutdown(struct conn_list *dest)
Definition packets_gen.c:2407
packet_type
packet_type
Definition packets_gen.h:1902
len
int len
Definition packhand.c:127
player_by_name
struct player * player_by_name(const char *name)
Definition player.c:881
player_by_user
struct player * player_by_user(const char *name)
Definition player.c:940
players_iterate_end
#define players_iterate_end
Definition player.h:539
players_iterate
#define players_iterate(_pplayer)
Definition player.h:534
is_human
#define is_human(plr)
Definition player.h:231
normal_player_count
int normal_player_count(void)
Definition plrhand.c:3208
plrhand.h
script_server_signal_emit
void script_server_signal_emit(const char *signal_name,...)
Definition script_server.c:408
script_server.h
cut_lagging_connection
static void cut_lagging_connection(struct connection *pconn)
Definition sernet.c:351
connection_ping
static void connection_ping(struct connection *pconn)
Definition sernet.c:1427
server_conn_close_callback
static void server_conn_close_callback(struct connection *pconn)
Definition sernet.c:342
send_lanserver_response
static void send_lanserver_response(void)
Definition sernet.c:1542
connections
static struct connection connections[MAX_NUM_CONNECTIONS]
Definition sernet.c:94
server_open_socket
int server_open_socket(void)
Definition sernet.c:1133
flush_packets
void flush_packets(void)
Definition sernet.c:376
init_connections
void init_connections(void)
Definition sernet.c:1362
really_close_connections
static void really_close_connections(void)
Definition sernet.c:304
server_make_connection
int server_make_connection(int new_sock, const char *client_addr, const char *client_ip)
Definition sernet.c:1071
handle_conn_pong
void handle_conn_pong(struct connection *pconn)
Definition sernet.c:1441
socklan
static int socklan
Definition sernet.c:98
listen_socks
static int * listen_socks
Definition sernet.c:96
current_internal
static char * current_internal
Definition sernet.c:152
listen_count
static int listen_count
Definition sernet.c:97
get_packet
static bool get_packet(struct connection *pconn, struct packet_to_handle *ppacket)
Definition sernet.c:451
send_ping_times_to_all
static void send_ping_times_to_all(void)
Definition sernet.c:1469
server_sniff_all_input
enum server_events server_sniff_all_input(void)
Definition sernet.c:522
close_connection
static void close_connection(struct connection *pconn)
Definition sernet.c:223
handle_client_heartbeat
void handle_client_heartbeat(struct connection *pconn)
Definition sernet.c:1461
readline_atexit
void readline_atexit(void)
Definition sernet.c:204
close_connections_and_socket
void close_connections_and_socket(void)
Definition sernet.c:255
finish_processing_request
static void finish_processing_request(struct connection *pconn)
Definition sernet.c:1409
start_processing_request
static void start_processing_request(struct connection *pconn, int request_id)
Definition sernet.c:1394
handle_stdin_close
static void handle_stdin_close(void)
Definition sernet.c:139
makeup_connection_name
static const char * makeup_connection_name(int *id)
Definition sernet.c:959
server_accept_connection
static int server_accept_connection(int sockfd)
Definition sernet.c:986
get_lanserver_announcement
static void get_lanserver_announcement(void)
Definition sernet.c:1493
no_input
static bool no_input
Definition sernet.c:130
incoming_client_packets
static void incoming_client_packets(struct connection *pconn)
Definition sernet.c:464
sernet.h
SERVER_LAN_TTL
#define SERVER_LAN_TTL
Definition sernet.h:25
server_events
server_events
Definition sernet.h:28
S_E_OTHERWISE
@ S_E_OTHERWISE
Definition sernet.h:30
S_E_END_OF_TURN_TIMEOUT
@ S_E_END_OF_TURN_TIMEOUT
Definition sernet.h:29
S_E_FORCE_END_OF_SNIFF
@ S_E_FORCE_END_OF_SNIFF
Definition sernet.h:31
BUF_SIZE
#define BUF_SIZE
Definition sernet.h:22
SERVER_LAN_VERSION
#define SERVER_LAN_VERSION
Definition sernet.h:26
SERVER_LAN_PORT
#define SERVER_LAN_PORT
Definition sernet.h:24
make_dir
bool make_dir(const char *pathname, int mode)
Definition shared.c:1783
get_multicast_group
char * get_multicast_group(bool ipv6_preferred)
Definition shared.c:1671
freeciv_storage_dir
char * freeciv_storage_dir(void)
Definition shared.c:678
shared.h
ARRAY_SIZE
#define ARRAY_SIZE(x)
Definition shared.h:85
DIRMODE_DEFAULT
#define DIRMODE_DEFAULT
Definition shared.h:252
MAX
#define MAX(x, y)
Definition shared.h:54
size
size_t size
Definition specvec.h:72
force_end_of_sniff
bool force_end_of_sniff
Definition srv_main.c:192
save_game_auto
void save_game_auto(const char *save_reason, enum autosave_type type)
Definition srv_main.c:1836
set_server_state
void set_server_state(enum server_states newstate)
Definition srv_main.c:345
srvarg
struct server_arguments srvarg
Definition srv_main.c:180
server_packet_input
bool server_packet_input(struct connection *pconn, void *packet, int type)
Definition srv_main.c:2090
server_quit
void fc__noreturn server_quit(void)
Definition srv_main.c:1914
server_state
enum server_states server_state(void)
Definition srv_main.c:337
srv_main.h
access_level_for_next_connection
enum cmdlevel access_level_for_next_connection(void)
Definition stdinhand.c:1436
handle_stdin_input_free
bool handle_stdin_input_free(struct connection *caller, char *str)
Definition stdinhand.c:4434
stdinhand.h
civ_game::tcptimeout
int tcptimeout
Definition game.h:195
civ_game::glob_observers
struct conn_list * glob_observers
Definition game.h:98
civ_game::netwait
int netwait
Definition game.h:168
civ_game::est_connections
struct conn_list * est_connections
Definition game.h:97
civ_game::info
struct packet_game_info info
Definition game.h:89
civ_game::autosaves
unsigned autosaves
Definition game.h:185
civ_game::save_timer
struct timer * save_timer
Definition game.h:217
civ_game::last_ping
time_t last_ping
Definition game.h:210
civ_game::additional_phase_seconds
int additional_phase_seconds
Definition game.h:212
civ_game::maxconnectionsperhost
int maxconnectionsperhost
Definition game.h:155
civ_game::pingtimeout
int pingtimeout
Definition game.h:173
civ_game::web_client_connections
struct conn_list * web_client_connections
Definition game.h:99
civ_game::phase_timer
struct timer * phase_timer
Definition game.h:211
civ_game::pingtime
int pingtime
Definition game.h:172
civ_game::all_connections
struct conn_list * all_connections
Definition game.h:96
civ_game::server
struct civ_game::@31::@35 server
civ_game::tinfo
struct packet_timeout_info tinfo
Definition game.h:91
civ_game::save_frequency
int save_frequency
Definition game.h:184
connection
Definition connection.h:136
connection::status
enum auth_status status
Definition connection.h:217
connection::buffer
struct socket_packet_buffer * buffer
Definition connection.h:153
connection::used
bool used
Definition connection.h:139
data_in
Definition dataio_raw.h:30
packet_conn_ping_info
Definition packets_gen.h:867
packet_conn_ping_info::connections
int connections
Definition packets_gen.h:868
packet_conn_ping_info::ping_time
float ping_time[MAX_NUM_CONNECTIONS]
Definition packets_gen.h:870
packet_conn_ping_info::conn_id
int conn_id[MAX_NUM_CONNECTIONS]
Definition packets_gen.h:869
packet_game_info::timeout
int timeout
Definition packets_gen.h:239
packet_timeout_info::seconds_to_phasedone
float seconds_to_phasedone
Definition packets_gen.h:269
packet_to_handle
Definition sernet.c:443
packet_to_handle::type
enum packet_type type
Definition sernet.c:445
packet_to_handle::data
void * data
Definition sernet.c:444
raw_data_out
Definition dataio_raw.h:35
server_arguments::bind_addr
char * bind_addr
Definition srv_main.h:34
server_arguments::exit_on_end
bool exit_on_end
Definition srv_main.h:53
server_arguments::announce
enum announce_type announce
Definition srv_main.h:60
server_arguments::quitidle
int quitidle
Definition srv_main.h:51
server_arguments::auth_enabled
bool auth_enabled
Definition srv_main.h:57
server_arguments::identity_name
char identity_name[256]
Definition srv_main.h:31
server_arguments::port
int port
Definition srv_main.h:36
setting
Definition settings.c:92
timer
Definition timing.c:81
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
fc_gethostname
int fc_gethostname(char *buf, size_t len)
Definition support.c:1007
fc_strerror
const char * fc_strerror(fc_errno err)
Definition support.c:609
fc_get_errno
fc_errno fc_get_errno(void)
Definition support.c:592
support.h
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:189
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
fc_errno
int fc_errno
Definition support.h:140
timer_destroy
void timer_destroy(struct timer *t)
Definition timing.c:208
timer_start
void timer_start(struct timer *t)
Definition timing.c:264
timer_new
struct timer * timer_new(enum timer_timetype type, enum timer_use use, const char *name)
Definition timing.c:160
timer_read_seconds
double timer_read_seconds(struct timer *t)
Definition timing.c:384
timer_renew
struct timer * timer_renew(struct timer *t, enum timer_timetype type, enum timer_use use, const char *name)
Definition timing.c:180
timing.h
TIMER_ACTIVE
@ TIMER_ACTIVE
Definition timing.h:46
TIMER_USER
@ TIMER_USER
Definition timing.h:42
fc_sockaddr
Definition netintf.h:70
fc_sockaddr::saddr
struct sockaddr saddr
Definition netintf.h:71
fc_sockaddr::saddr_in4
struct sockaddr_in saddr_in4
Definition netintf.h:72
send_updated_vote_totals
void send_updated_vote_totals(struct conn_list *dest)
Definition voting.c:866
voting.h