Freeciv-3.2: /fast/freeciv/nightly/S3_2/server/sernet.c Source File

Freeciv-3.2

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