Do not build gtk3.22-client by default
[freeciv.git] / server / sernet.c
blob46ec7d57f6070b88e148d24c8acbd88268ae2063
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.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 #include "fc_prehdrs.h"
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
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
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"
72 /* common */
73 #include "dataio.h"
74 #include "events.h"
75 #include "game.h"
76 #include "packets.h"
78 /* server/scripting */
79 #include "script_server.h"
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"
92 #include "sernet.h"
94 static struct connection connections[MAX_NUM_CONNECTIONS];
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
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
123 #define PROCESSING_TIME_STATISTICS 0
125 static int server_accept_connection(int sockfd);
126 static void start_processing_request(struct connection *pconn,
127 int request_id);
128 static void finish_processing_request(struct connection *pconn);
129 static void connection_ping(struct connection *pconn);
130 static void send_ping_times_to_all(void);
132 static void get_lanserver_announcement(void);
133 static void send_lanserver_response(void);
135 static bool no_input = FALSE;
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 /*****************************************************************************
142 This happens if you type an EOF character with nothing on the current line.
143 *****************************************************************************/
144 static void handle_stdin_close(void)
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 */
155 #endif /* FREECIV_HAVE_LIBREADLINE || (!FREECIV_SOCKET_ZERO_NOT_STDIN && !FREECIV_HAVE_LIBREADLINE) */
157 #ifdef FREECIV_HAVE_LIBREADLINE
158 /****************************************************************************/
160 #define HISTORY_FILENAME "freeciv-server_history"
161 #define HISTORY_LENGTH 100
163 static char *history_file = NULL;
165 static bool readline_handled_input = FALSE;
167 static bool readline_initialized = FALSE;
169 /*****************************************************************************
170 Readline callback for input.
171 *****************************************************************************/
172 static void handle_readline_input_callback(char *line)
174 char *line_internal;
176 if (no_input)
177 return;
179 if (!line) {
180 handle_stdin_close(); /* maybe print an 'are you sure?' message? */
181 return;
184 if (line[0] != '\0')
185 add_history(line);
187 con_prompt_enter(); /* just got an 'Enter' hit */
188 line_internal = local_to_internal_string_malloc(line);
189 (void) handle_stdin_input(NULL, line_internal);
190 free(line_internal);
191 free(line);
193 readline_handled_input = TRUE;
195 #endif /* FREECIV_HAVE_LIBREADLINE */
197 /****************************************************************************
198 Close the connection (very low-level). See also
199 server_conn_close_callback().
200 ****************************************************************************/
201 static void close_connection(struct connection *pconn)
203 if (!pconn) {
204 return;
207 if (pconn->server.ping_timers != NULL) {
208 timer_list_destroy(pconn->server.ping_timers);
209 pconn->server.ping_timers = NULL;
212 conn_pattern_list_destroy(pconn->server.ignore_list);
213 pconn->server.ignore_list = NULL;
215 /* safe to do these even if not in lists: */
216 conn_list_remove(game.glob_observers, pconn);
217 conn_list_remove(game.all_connections, pconn);
218 conn_list_remove(game.est_connections, pconn);
220 pconn->playing = NULL;
221 pconn->access_level = ALLOW_NONE;
222 connection_common_close(pconn);
224 send_updated_vote_totals(NULL);
227 /*****************************************************************************
228 Close all network stuff: connections, listening sockets, metaserver
229 connection...
230 *****************************************************************************/
231 void close_connections_and_socket(void)
233 int i;
235 lsend_packet_server_shutdown(game.all_connections);
237 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
238 if (connections[i].used) {
239 close_connection(&connections[i]);
241 conn_list_destroy(connections[i].self);
244 /* Remove the game connection lists and make sure they are empty. */
245 conn_list_destroy(game.glob_observers);
246 conn_list_destroy(game.all_connections);
247 conn_list_destroy(game.est_connections);
249 for (i = 0; i < listen_count; i++) {
250 fc_closesocket(listen_socks[i]);
252 FC_FREE(listen_socks);
254 if (srvarg.announce != ANNOUNCE_NONE) {
255 fc_closesocket(socklan);
258 #ifdef FREECIV_HAVE_LIBREADLINE
259 if (history_file) {
260 write_history(history_file);
261 history_truncate_file(history_file, HISTORY_LENGTH);
262 free(history_file);
263 history_file = NULL;
264 clear_history();
266 #endif /* FREECIV_HAVE_LIBREADLINE */
268 send_server_info_to_metaserver(META_GOODBYE);
269 server_close_meta();
271 packets_deinit();
272 fc_shutdown_network();
275 /****************************************************************************
276 Now really close connections marked as 'is_closing'.
277 Do this here to avoid recursive sending.
278 ****************************************************************************/
279 static void really_close_connections(void)
281 struct connection *closing[MAX_NUM_CONNECTIONS];
282 struct connection *pconn;
283 int i, num;
285 do {
286 num = 0;
288 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
289 pconn = connections + i;
290 if (pconn->used && pconn->server.is_closing) {
291 closing[num++] = pconn;
292 /* Remove closing connections from the lists (hard detach)
293 * to avoid sending to closing connections. */
294 conn_list_remove(game.glob_observers, pconn);
295 conn_list_remove(game.est_connections, pconn);
296 conn_list_remove(game.all_connections, pconn);
297 if (NULL != conn_get_player(pconn)) {
298 conn_list_remove(conn_get_player(pconn)->connections, pconn);
303 for (i = 0; i < num; i++) {
304 /* Now really close them. */
305 pconn = closing[i];
306 lost_connection_to_client(pconn);
307 close_connection(pconn);
309 } while (0 < num); /* May some errors occurred, let's check. */
312 /****************************************************************************
313 Break a client connection. You should almost always use
314 connection_close_server() instead of calling this function directly.
315 ****************************************************************************/
316 static void server_conn_close_callback(struct connection *pconn)
318 /* Do as little as possible here to avoid recursive evil. */
319 pconn->server.is_closing = TRUE;
322 /****************************************************************************
323 If a connection lags too much this function is called and we try to cut
325 ****************************************************************************/
326 static void cut_lagging_connection(struct connection *pconn)
328 if (!pconn->server.is_closing
329 && game.server.tcptimeout != 0
330 && pconn->last_write
331 && conn_list_size(game.all_connections) > 1
332 && pconn->access_level != ALLOW_HACK
333 && timer_read_seconds(pconn->last_write) > game.server.tcptimeout) {
334 /* Cut the connections to players who lag too much. This
335 * usually happens because client animation slows the client
336 * too much and it can't keep up with the server. We don't
337 * cut HACK connections, or cut in single-player games, since
338 * it wouldn't help the game progress. For other connections
339 * the best thing to do when they lag too much is to be
340 * disconnected and reconnect. */
341 log_verbose("connection (%s) cut due to lagging player",
342 conn_description(pconn));
343 connection_close_server(pconn, _("lagging connection"));
347 /****************************************************************************
348 Attempt to flush all information in the send buffers for upto 'netwait'
349 seconds.
350 *****************************************************************************/
351 void flush_packets(void)
353 int i;
354 int max_desc;
355 fd_set writefs, exceptfs;
356 fc_timeval tv;
357 time_t start;
359 (void) time(&start);
361 for(;;) {
362 tv.tv_sec = (game.server.netwait - (time(NULL) - start));
363 tv.tv_usec = 0;
365 if (tv.tv_sec < 0) {
366 return;
369 FC_FD_ZERO(&writefs);
370 FC_FD_ZERO(&exceptfs);
371 max_desc = -1;
373 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
374 struct connection *pconn = &connections[i];
376 if (pconn->used
377 && !pconn->server.is_closing
378 && 0 < pconn->send_buffer->ndata) {
379 FD_SET(pconn->sock, &writefs);
380 FD_SET(pconn->sock, &exceptfs);
381 max_desc = MAX(pconn->sock, max_desc);
385 if (max_desc == -1) {
386 return;
389 if (fc_select(max_desc + 1, NULL, &writefs, &exceptfs, &tv) <= 0) {
390 return;
393 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) { /* check for freaky players */
394 struct connection *pconn = &connections[i];
396 if (pconn->used && !pconn->server.is_closing) {
397 if (FD_ISSET(pconn->sock, &exceptfs)) {
398 log_verbose("connection (%s) cut due to exception data",
399 conn_description(pconn));
400 connection_close_server(pconn, _("network exception"));
401 } else {
402 if(pconn->send_buffer && pconn->send_buffer->ndata > 0) {
403 if(FD_ISSET(pconn->sock, &writefs)) {
404 flush_connection_send_buffer_all(pconn);
405 } else {
406 cut_lagging_connection(pconn);
415 struct packet_to_handle {
416 void *data;
417 enum packet_type type;
420 /*****************************************************************************
421 Simplify a loop by wrapping get_packet_from_connection.
422 *****************************************************************************/
423 static bool get_packet(struct connection *pconn,
424 struct packet_to_handle *ppacket)
426 ppacket->data = get_packet_from_connection(pconn, &ppacket->type);
428 return NULL != ppacket->data;
431 /*****************************************************************************
432 Handle all incoming packets on a client connection.
433 Precondition - we have read_socket_data.
434 Postcondition - there are no more packets to handle on this connection.
435 *****************************************************************************/
436 static void incoming_client_packets(struct connection *pconn)
438 struct packet_to_handle packet;
439 #if PROCESSING_TIME_STATISTICS
440 struct timer *request_time = NULL;
441 #endif
443 while (get_packet(pconn, &packet)) {
444 bool command_ok;
446 #if PROCESSING_TIME_STATISTICS
447 int request_id;
449 request_time = timer_renew(request_time, TIMER_USER, TIMER_ACTIVE);
450 timer_start(request_time);
451 #endif /* PROCESSING_TIME_STATISTICS */
453 pconn->server.last_request_id_seen
454 = get_next_request_id(pconn->server.last_request_id_seen);
456 #if PROCESSING_TIME_STATISTICS
457 request_id = pconn->server.last_request_id_seen;
458 #endif /* PROCESSING_TIME_STATISTICS */
460 connection_do_buffer(pconn);
461 start_processing_request(pconn, pconn->server.last_request_id_seen);
463 command_ok = server_packet_input(pconn, packet.data, packet.type);
464 free(packet.data);
466 finish_processing_request(pconn);
467 connection_do_unbuffer(pconn);
469 #if PROCESSING_TIME_STATISTICS
470 log_verbose("processed request %d in %gms", request_id,
471 timer_read_seconds(request_time) * 1000.0);
472 #endif /* PROCESSING_TIME_STATISTICS */
474 if (!command_ok) {
475 connection_close_server(pconn, _("rejected"));
479 #if PROCESSING_TIME_STATISTICS
480 timer_destroy(request_time);
481 #endif /* PROCESSING_TIME_STATISTICS */
485 /*****************************************************************************
486 Get and handle:
487 - new connections,
488 - input from connections,
489 - input from server operator in stdin
491 This function also handles prompt printing, via the con_prompt_*
492 functions. That is, other functions should not need to do so. --dwp
493 *****************************************************************************/
494 enum server_events server_sniff_all_input(void)
496 int i, s;
497 int max_desc;
498 bool excepting;
499 fd_set readfs, writefs, exceptfs;
500 fc_timeval tv;
501 #ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
502 char *bufptr;
503 #endif
505 con_prompt_init();
507 #ifdef FREECIV_HAVE_LIBREADLINE
509 if (!no_input && !readline_initialized) {
510 char *home_dir = user_home_dir();
512 if (home_dir) {
513 int fcdl = strlen(home_dir) + 1 + strlen(".freeciv") + 1;
514 char *fc_dir = fc_malloc(fcdl);
516 if (fc_dir != NULL) {
517 fc_snprintf(fc_dir, fcdl, "%s/.freeciv", home_dir);
519 if (make_dir(fc_dir)) {
520 history_file
521 = fc_malloc(strlen(fc_dir) + 1 + strlen(HISTORY_FILENAME) + 1);
522 if (history_file) {
523 strcpy(history_file, fc_dir);
524 strcat(history_file, "/");
525 strcat(history_file, HISTORY_FILENAME);
526 using_history();
527 read_history(history_file);
530 FC_FREE(fc_dir);
534 rl_initialize();
535 rl_callback_handler_install((char *) "> ",
536 handle_readline_input_callback);
537 rl_attempted_completion_function = freeciv_completion;
539 readline_initialized = TRUE;
540 atexit(rl_callback_handler_remove);
543 #endif /* FREECIV_HAVE_LIBREADLINE */
545 while (TRUE) {
546 con_prompt_on(); /* accepting new input */
548 if (force_end_of_sniff) {
549 force_end_of_sniff = FALSE;
550 con_prompt_off();
551 return S_E_FORCE_END_OF_SNIFF;
554 get_lanserver_announcement();
556 /* end server if no players for 'srvarg.quitidle' seconds,
557 * but only if at least one player has previously connected. */
558 if (srvarg.quitidle != 0) {
559 static time_t last_noplayers;
560 static bool conns;
562 if (conn_list_size(game.est_connections) > 0) {
563 conns = TRUE;
565 if (conns && conn_list_size(game.est_connections) == 0) {
566 if (last_noplayers != 0) {
567 if (time(NULL) > last_noplayers + srvarg.quitidle) {
568 save_game_auto("Lost all connections", AS_QUITIDLE);
570 if (srvarg.exit_on_end) {
571 log_normal(_("Shutting down for lack of players."));
572 set_meta_message_string("shutting down for lack of players");
573 } else {
574 log_normal(_("Restarting for lack of players."));
575 set_meta_message_string("restarting for lack of players");
577 (void) send_server_info_to_metaserver(META_INFO);
579 set_server_state(S_S_OVER);
580 force_end_of_sniff = TRUE;
582 if (srvarg.exit_on_end) {
583 /* No need for anything more; just quit. */
584 server_quit();
587 /* Do not restart before someone has connected and left again */
588 conns = FALSE;
590 } else {
591 last_noplayers = time(NULL);
593 if (srvarg.exit_on_end) {
594 log_normal(_("Shutting down in %d seconds for lack of players."),
595 srvarg.quitidle);
597 set_meta_message_string(N_("shutting down soon for lack of players"));
598 } else {
599 log_normal(_("Restarting in %d seconds for lack of players."),
600 srvarg.quitidle);
602 set_meta_message_string(N_("restarting soon for lack of players"));
604 (void) send_server_info_to_metaserver(META_INFO);
606 } else {
607 last_noplayers = 0;
611 /* Pinging around for statistics */
612 if (time(NULL) > (game.server.last_ping + game.server.pingtime)) {
613 /* send data about the previous run */
614 send_ping_times_to_all();
616 conn_list_iterate(game.all_connections, pconn) {
617 if ((!pconn->server.is_closing
618 && 0 < timer_list_size(pconn->server.ping_timers)
619 && timer_read_seconds(timer_list_front
620 (pconn->server.ping_timers))
621 > game.server.pingtimeout)
622 || pconn->ping_time > game.server.pingtimeout) {
623 /* cut mute players, except for hack-level ones */
624 if (pconn->access_level == ALLOW_HACK) {
625 log_verbose("connection (%s) [hack-level] ping timeout ignored",
626 conn_description(pconn));
627 } else {
628 log_verbose("connection (%s) cut due to ping timeout",
629 conn_description(pconn));
630 connection_close_server(pconn, _("ping timeout"));
632 } else if (pconn->established) {
633 /* We don't send ping to connection not established, because
634 * we wouldn't be able to handle asynchronous ping/pong with
635 * different packet header size. */
636 connection_ping(pconn);
638 } conn_list_iterate_end;
639 game.server.last_ping = time(NULL);
642 /* if we've waited long enough after a failure, respond to the client */
643 conn_list_iterate(game.all_connections, pconn) {
644 if (srvarg.auth_enabled
645 && !pconn->server.is_closing
646 && pconn->server.status != AS_ESTABLISHED) {
647 auth_process_status(pconn);
649 } conn_list_iterate_end
651 /* Don't wait if timeout == -1 (i.e. on auto games) */
652 if (S_S_RUNNING == server_state() && game.info.timeout == -1) {
653 call_ai_refresh();
654 script_server_signal_emit("pulse", 0);
655 (void) send_server_info_to_metaserver(META_REFRESH);
656 return S_E_END_OF_TURN_TIMEOUT;
659 tv.tv_sec = 1;
660 tv.tv_usec = 0;
662 FC_FD_ZERO(&readfs);
663 FC_FD_ZERO(&writefs);
664 FC_FD_ZERO(&exceptfs);
666 if (!no_input) {
667 #ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
668 fc_init_console();
669 #else /* FREECIV_SOCKET_ZERO_NOT_STDIN */
670 # if !defined(__VMS)
671 FD_SET(0, &readfs);
672 # endif /* VMS */
673 #endif /* FREECIV_SOCKET_ZERO_NOT_STDIN */
676 max_desc = 0;
677 for (i = 0; i < listen_count; i++) {
678 FD_SET(listen_socks[i], &readfs);
679 FD_SET(listen_socks[i], &exceptfs);
680 max_desc = MAX(max_desc, listen_socks[i]);
683 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
684 struct connection *pconn = connections + i;
686 if (pconn->used && !pconn->server.is_closing) {
687 FD_SET(pconn->sock, &readfs);
688 if (0 < pconn->send_buffer->ndata) {
689 FD_SET(pconn->sock, &writefs);
691 FD_SET(pconn->sock, &exceptfs);
692 max_desc = MAX(pconn->sock, max_desc);
695 con_prompt_off(); /* output doesn't generate a new prompt */
697 if (fc_select(max_desc + 1, &readfs, &writefs, &exceptfs, &tv) == 0) {
698 /* timeout */
699 call_ai_refresh();
700 script_server_signal_emit("pulse", 0);
701 (void) send_server_info_to_metaserver(META_REFRESH);
702 if (current_turn_timeout() > 0
703 && S_S_RUNNING == server_state()
704 && game.server.phase_timer
705 && (timer_read_seconds(game.server.phase_timer)
706 > game.tinfo.seconds_to_phasedone)) {
707 con_prompt_off();
708 return S_E_END_OF_TURN_TIMEOUT;
710 if ((game.server.autosaves & (1 << AS_TIMER))
711 && S_S_RUNNING == server_state()
712 && (timer_read_seconds(game.server.save_timer)
713 >= game.server.save_frequency * 60)) {
714 save_game_auto("Timer", AS_TIMER);
715 game.server.save_timer = timer_renew(game.server.save_timer,
716 TIMER_USER, TIMER_ACTIVE);
717 timer_start(game.server.save_timer);
720 if (!no_input) {
721 #if defined(__VMS)
723 struct {
724 short numchars;
725 char firstchar;
726 char reserved;
727 int reserved2;
728 } ttchar;
729 unsigned long status;
731 status = sys$qiow(EFN$C_ENF, tt_chan,
732 IO$_SENSEMODE | IO$M_TYPEAHDCNT, 0, 0, 0,
733 &ttchar, sizeof(ttchar), 0, 0, 0, 0);
734 if (!$VMS_STATUS_SUCCESS(status)) {
735 lib$stop(status);
737 if (ttchar.numchars) {
738 FD_SET(0, &readfs);
739 } else {
740 continue;
743 #else /* !__VMS */
744 #ifndef FREECIV_SOCKET_ZERO_NOT_STDIN
745 really_close_connections();
746 continue;
747 #endif /* FREECIV_SOCKET_ZERO_NOT_STDIN */
748 #endif /* !__VMS */
752 excepting = FALSE;
753 for (i = 0; i < listen_count; i++) {
754 if (FD_ISSET(listen_socks[i], &exceptfs)) {
755 excepting = TRUE;
756 break;
759 if (excepting) { /* handle Ctrl-Z suspend/resume */
760 continue;
762 for (i = 0; i < listen_count; i++) {
763 s = listen_socks[i];
764 if (FD_ISSET(s, &readfs)) { /* new players connects */
765 log_verbose("got new connection");
766 if (-1 == server_accept_connection(s)) {
767 /* There will be a log_error() message from
768 * server_accept_connection() if something
769 * goes wrong, so no need to make another
770 * error-level message here. */
771 log_verbose("failed accepting connection");
775 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
776 /* check for freaky players */
777 struct connection *pconn = &connections[i];
779 if (pconn->used
780 && !pconn->server.is_closing
781 && FD_ISSET(pconn->sock, &exceptfs)) {
782 log_verbose("connection (%s) cut due to exception data",
783 conn_description(pconn));
784 connection_close_server(pconn, _("network exception"));
787 #ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
788 if (!no_input && (bufptr = fc_read_console())) {
789 char *bufptr_internal = local_to_internal_string_malloc(bufptr);
791 con_prompt_enter(); /* will need a new prompt, regardless */
792 handle_stdin_input(NULL, bufptr_internal);
793 free(bufptr_internal);
795 #else /* !FREECIV_SOCKET_ZERO_NOT_STDIN */
796 if (!no_input && FD_ISSET(0, &readfs)) { /* input from server operator */
797 #ifdef FREECIV_HAVE_LIBREADLINE
798 rl_callback_read_char();
799 if (readline_handled_input) {
800 readline_handled_input = FALSE;
801 con_prompt_enter_clear();
803 continue;
804 #else /* !FREECIV_HAVE_LIBREADLINE */
805 ssize_t didget;
806 char *buffer = NULL; /* Must be NULL when calling getline() */
807 char *buf_internal;
809 #ifdef HAVE_GETLINE
810 size_t len = 0;
812 didget = getline(&buffer, &len, stdin);
813 if (didget >= 1) {
814 buffer[didget-1] = '\0'; /* overwrite newline character */
815 didget--;
816 log_debug("Got line: \"%s\" (%ld, %ld)", buffer,
817 (long int) didget, (long int) len);
819 #else /* HAVE_GETLINE */
820 buffer = malloc(BUF_SIZE + 1);
822 didget = read(0, buffer, BUF_SIZE);
823 if (didget > 0) {
824 buffer[didget] = '\0';
825 } else {
826 didget = -1; /* error or end-of-file: closing stdin... */
828 #endif /* HAVE_GETLINE */
829 if (didget < 0) {
830 handle_stdin_close();
833 con_prompt_enter(); /* will need a new prompt, regardless */
835 if (didget >= 0) {
836 buf_internal = local_to_internal_string_malloc(buffer);
837 handle_stdin_input(NULL, buf_internal);
838 free(buf_internal);
840 free(buffer);
841 #endif /* !FREECIV_HAVE_LIBREADLINE */
842 } else
843 #endif /* !FREECIV_SOCKET_ZERO_NOT_STDIN */
845 { /* input from a player */
846 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
847 struct connection *pconn = connections + i;
848 int nb;
850 if (!pconn->used
851 || pconn->server.is_closing
852 || !FD_ISSET(pconn->sock, &readfs)) {
853 continue;
856 nb = read_socket_data(pconn->sock, pconn->buffer);
857 if (0 <= nb) {
858 /* We read packets; now handle them. */
859 incoming_client_packets(pconn);
860 } else if (-2 == nb) {
861 connection_close_server(pconn, _("client disconnected"));
862 } else {
863 /* Read failure; the connection is closed. */
864 connection_close_server(pconn, _("read error"));
868 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
869 struct connection *pconn = &connections[i];
871 if (pconn->used
872 && !pconn->server.is_closing
873 && pconn->send_buffer
874 && pconn->send_buffer->ndata > 0) {
875 if (FD_ISSET(pconn->sock, &writefs)) {
876 flush_connection_send_buffer_all(pconn);
877 } else {
878 cut_lagging_connection(pconn);
882 really_close_connections();
883 break;
886 con_prompt_off();
888 call_ai_refresh();
889 script_server_signal_emit("pulse", 0);
891 if (current_turn_timeout() > 0
892 && S_S_RUNNING == server_state()
893 && game.server.phase_timer
894 && (timer_read_seconds(game.server.phase_timer)
895 > game.tinfo.seconds_to_phasedone)) {
896 return S_E_END_OF_TURN_TIMEOUT;
898 if ((game.server.autosaves & (1 << AS_TIMER))
899 && S_S_RUNNING == server_state()
900 && (timer_read_seconds(game.server.save_timer)
901 >= game.server.save_frequency * 60)) {
902 save_game_auto("Timer", AS_TIMER);
903 game.server.save_timer = timer_renew(game.server.save_timer,
904 TIMER_USER, TIMER_ACTIVE);
905 timer_start(game.server.save_timer);
908 return S_E_OTHERWISE;
911 /********************************************************************
912 Make up a name for the connection, before we get any data from
913 it to use as a sensible name. Name will be 'c' + integer,
914 guaranteed not to be the same as any other connection name,
915 nor player name nor user name, nor connection id (avoid possible
916 confusions). Returns pointer to static buffer, and fills in
917 (*id) with chosen value.
918 ********************************************************************/
919 static const char *makeup_connection_name(int *id)
921 static unsigned short i = 0;
922 static char name[MAX_LEN_NAME];
924 for(;;) {
925 if (i==(unsigned short)-1) i++; /* don't use 0 */
926 fc_snprintf(name, sizeof(name), "c%u", (unsigned int)++i);
927 if (NULL == player_by_name(name)
928 && NULL == player_by_user(name)
929 && NULL == conn_by_number(i)
930 && NULL == conn_by_user(name)) {
931 *id = i;
932 return name;
937 /********************************************************************
938 Server accepts connection from client:
939 Low level socket stuff, and basic-initialize the connection struct.
940 Returns 0 on success, -1 on failure (bad accept(), or too many
941 connections).
942 ********************************************************************/
943 static int server_accept_connection(int sockfd)
945 /* This used to have size_t for some platforms. If this is necessary
946 * it should be done with a configure check not a platform check. */
947 socklen_t fromlen;
949 int new_sock;
950 union fc_sockaddr fromend;
951 bool nameinfo = FALSE;
952 #ifdef FREECIV_IPV6_SUPPORT
953 char host[NI_MAXHOST], service[NI_MAXSERV];
954 char dst[INET6_ADDRSTRLEN];
955 #else /* IPv6 support */
956 struct hostent *from;
957 const char *host = NULL;
958 const char *dst;
959 #endif /* IPv6 support */
961 fromlen = sizeof(fromend);
963 if ((new_sock = accept(sockfd, &fromend.saddr, &fromlen)) == -1) {
964 log_error("accept failed: %s", fc_strerror(fc_get_errno()));
965 return -1;
968 #ifdef FREECIV_IPV6_SUPPORT
969 if (fromend.saddr.sa_family == AF_INET6) {
970 inet_ntop(AF_INET6, &fromend.saddr_in6.sin6_addr,
971 dst, sizeof(dst));
972 } else if (fromend.saddr.sa_family == AF_INET) {
973 inet_ntop(AF_INET, &fromend.saddr_in4.sin_addr, dst, sizeof(dst));
974 } else {
975 fc_assert(FALSE);
977 log_error("Unsupported address family in server_accept_connection()");
979 return -1;
981 #else /* IPv6 support */
982 dst = inet_ntoa(fromend.saddr_in4.sin_addr);
983 #endif /* IPv6 support */
985 if (0 != game.server.maxconnectionsperhost) {
986 int count = 0;
988 conn_list_iterate(game.all_connections, pconn) {
989 if (0 != strcmp(dst, pconn->server.ipaddr)) {
990 continue;
992 if (++count >= game.server.maxconnectionsperhost) {
993 log_verbose("Rejecting new connection from %s: maximum number of "
994 "connections for this address exceeded (%d).",
995 dst, game.server.maxconnectionsperhost);
997 /* Disconnect the accepted socket. */
998 fc_closesocket(new_sock);
1000 return -1;
1002 } conn_list_iterate_end;
1005 #ifdef FREECIV_IPV6_SUPPORT
1006 nameinfo = (0 == getnameinfo(&fromend.saddr, fromlen, host, NI_MAXHOST,
1007 service, NI_MAXSERV, NI_NUMERICSERV)
1008 && '\0' != host[0]);
1009 #else /* IPv6 support */
1010 from = gethostbyaddr((char *) &fromend.saddr_in4.sin_addr,
1011 sizeof(fromend.saddr_in4.sin_addr), AF_INET);
1012 if (NULL != from && '\0' != from->h_name[0]) {
1013 host = from->h_name;
1014 nameinfo = TRUE;
1016 #endif /* IPv6 support */
1018 return server_make_connection(new_sock,
1019 (nameinfo ? host : dst), dst);
1022 /********************************************************************
1023 Server accepts connection from client:
1024 Low level socket stuff, and basic-initialize the connection struct.
1025 Returns 0 on success, -1 on failure (bad accept(), or too many
1026 connections).
1027 ********************************************************************/
1028 int server_make_connection(int new_sock, const char *client_addr, const char *client_ip)
1030 struct timer *timer;
1031 int i;
1033 fc_nonblock(new_sock);
1035 for(i=0; i<MAX_NUM_CONNECTIONS; i++) {
1036 struct connection *pconn = &connections[i];
1037 if (!pconn->used) {
1038 connection_common_init(pconn);
1039 pconn->sock = new_sock;
1040 pconn->observer = FALSE;
1041 pconn->playing = NULL;
1042 pconn->capability[0] = '\0';
1043 pconn->access_level = access_level_for_next_connection();
1044 pconn->notify_of_writable_data = NULL;
1045 pconn->server.currently_processed_request_id = 0;
1046 pconn->server.last_request_id_seen = 0;
1047 pconn->server.auth_tries = 0;
1048 pconn->server.auth_settime = 0;
1049 pconn->server.status = AS_NOT_ESTABLISHED;
1050 pconn->server.ping_timers = timer_list_new_full(timer_destroy);
1051 pconn->server.granted_access_level = pconn->access_level;
1052 pconn->server.ignore_list =
1053 conn_pattern_list_new_full(conn_pattern_destroy);
1054 pconn->server.is_closing = FALSE;
1055 pconn->ping_time = -1.0;
1056 pconn->incoming_packet_notify = NULL;
1057 pconn->outgoing_packet_notify = NULL;
1059 sz_strlcpy(pconn->username, makeup_connection_name(&pconn->id));
1060 sz_strlcpy(pconn->addr, client_addr);
1061 sz_strlcpy(pconn->server.ipaddr, client_ip);
1063 conn_list_append(game.all_connections, pconn);
1065 log_verbose("connection (%s) from %s (%s)",
1066 pconn->username, pconn->addr, pconn->server.ipaddr);
1067 /* Give a ping timeout to send the PACKET_SERVER_JOIN_REQ, or close
1068 * the mute connection. This timer will be canceled into
1069 * connecthand.c:handle_login_request(). */
1070 timer = timer_new(TIMER_USER, TIMER_ACTIVE);
1071 timer_start(timer);
1072 timer_list_append(pconn->server.ping_timers, timer);
1073 return 0;
1077 log_error("maximum number of connections reached");
1078 fc_closesocket(new_sock);
1079 return -1;
1082 /********************************************************************
1083 open server socket to be used to accept client connections
1084 and open a server socket for server LAN announcements.
1085 ********************************************************************/
1086 int server_open_socket(void)
1088 /* setup socket address */
1089 union fc_sockaddr addr;
1090 #ifdef HAVE_IP_MREQN
1091 struct ip_mreqn mreq4;
1092 #else
1093 struct ip_mreq mreq4;
1094 #endif
1095 const char *cause, *group;
1096 int j, on, s;
1097 int lan_family;
1098 struct fc_sockaddr_list *list;
1099 int name_count;
1100 fc_errno eno = 0;
1101 union fc_sockaddr *problematic = NULL;
1103 #ifdef FREECIV_IPV6_SUPPORT
1104 struct ipv6_mreq mreq6;
1105 #endif
1107 log_verbose("Server attempting to listen on %s:%d",
1108 srvarg.bind_addr ? srvarg.bind_addr : "(any)",
1109 srvarg.port);
1111 /* Any supported family will do */
1112 list = net_lookup_service(srvarg.bind_addr, srvarg.port, FC_ADDR_ANY);
1114 name_count = fc_sockaddr_list_size(list);
1116 /* Lookup addresses to bind. */
1117 if (name_count <= 0) {
1118 log_fatal(_("Server: bad address: <%s:%d>."),
1119 srvarg.bind_addr ? srvarg.bind_addr : "(none)", srvarg.port);
1120 exit(EXIT_FAILURE);
1123 cause = "internal"; /* If cause is not overwritten but gets printed... */
1124 on = 1;
1126 /* Loop to create sockets, bind, listen. */
1127 listen_socks = fc_calloc(name_count, sizeof(listen_socks[0]));
1128 listen_count = 0;
1130 fc_sockaddr_list_iterate(list, paddr) {
1131 /* Create socket for client connections. */
1132 s = socket(paddr->saddr.sa_family, SOCK_STREAM, 0);
1133 if (s == -1) {
1134 /* Probably EAFNOSUPPORT or EPROTONOSUPPORT.
1135 * Kernel might have disabled AF_INET6. */
1136 eno = fc_get_errno();
1137 cause = "socket";
1138 problematic = paddr;
1139 continue;
1142 #ifndef FREECIV_HAVE_WINSOCK
1143 /* SO_REUSEADDR considered harmful on Win, necessary otherwise */
1144 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1145 (char *)&on, sizeof(on)) == -1) {
1146 log_error("setsockopt SO_REUSEADDR failed: %s",
1147 fc_strerror(fc_get_errno()));
1148 sockaddr_debug(paddr, LOG_NORMAL);
1150 #endif /* FREECIV_HAVE_WINSOCK */
1152 /* AF_INET6 sockets should use IPv6 only,
1153 * without stealing IPv4 from AF_INET sockets. */
1154 #ifdef FREECIV_IPV6_SUPPORT
1155 if (paddr->saddr.sa_family == AF_INET6) {
1156 #ifdef IPV6_V6ONLY
1157 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
1158 (char *)&on, sizeof(on)) == -1) {
1159 log_error("setsockopt IPV6_V6ONLY failed: %s",
1160 fc_strerror(fc_get_errno()));
1161 sockaddr_debug(paddr, LOG_DEBUG);
1163 #endif /* IPV6_V6ONLY */
1165 #endif /* IPv6 support */
1167 if (bind(s, &paddr->saddr, sockaddr_size(paddr)) == -1) {
1168 eno = fc_get_errno();
1169 cause = "bind";
1170 problematic = paddr;
1172 if (eno == EADDRNOTAVAIL) {
1173 /* Close only this socket. This address is not available.
1174 * This can happen with the IPv6 wildcard address if this
1175 * machine has no IPv6 interfaces. */
1176 /* If you change this logic, be sure to make clientside checking
1177 * of acceptable port to match. */
1178 fc_closesocket(s);
1179 continue;
1180 } else {
1181 /* Close all sockets. Another program might have bound to
1182 * one of our addresses, and might hijack some of our
1183 * connections. */
1184 fc_closesocket(s);
1185 for (j = 0; j < listen_count; j++) {
1186 fc_closesocket(listen_socks[j]);
1188 listen_count = 0;
1189 break;
1193 if (listen(s, MAX_NUM_CONNECTIONS) == -1) {
1194 eno = fc_get_errno();
1195 cause = "listen";
1196 problematic = paddr;
1197 fc_closesocket(s);
1198 continue;
1201 listen_socks[listen_count++] = s;
1202 } fc_sockaddr_list_iterate_end;
1204 if (listen_count == 0) {
1205 log_fatal("%s failure: %s (%d failed)", cause, fc_strerror(eno), name_count);
1206 if (problematic != NULL) {
1207 sockaddr_debug(problematic, LOG_NORMAL);
1209 fc_sockaddr_list_iterate(list, paddr) {
1210 /* Do not list already logged 'problematic' again */
1211 if (paddr != problematic) {
1212 sockaddr_debug(paddr, LOG_DEBUG);
1214 } fc_sockaddr_list_iterate_end;
1215 exit(EXIT_FAILURE);
1218 fc_sockaddr_list_destroy(list);
1220 connections_set_close_callback(server_conn_close_callback);
1222 if (srvarg.announce == ANNOUNCE_NONE) {
1223 return 0;
1226 #ifdef FREECIV_IPV6_SUPPORT
1227 if (srvarg.announce == ANNOUNCE_IPV6) {
1228 lan_family = AF_INET6;
1229 } else
1230 #endif /* IPV6 support */
1232 lan_family = AF_INET;
1235 /* Create socket for server LAN announcements */
1236 if ((socklan = socket(lan_family, SOCK_DGRAM, 0)) < 0) {
1237 log_error("Announcement socket failed: %s", fc_strerror(fc_get_errno()));
1238 return 0; /* FIXME: Should this cause hard error as exit(EXIT_FAILURE).
1239 * It's failure to do as commandline parameters requested after all */
1242 if (setsockopt(socklan, SOL_SOCKET, SO_REUSEADDR,
1243 (char *)&on, sizeof(on)) == -1) {
1244 log_error("SO_REUSEADDR failed: %s", fc_strerror(fc_get_errno()));
1247 fc_nonblock(socklan);
1249 group = get_multicast_group(srvarg.announce == ANNOUNCE_IPV6);
1251 memset(&addr, 0, sizeof(addr));
1253 addr.saddr.sa_family = lan_family;
1255 #ifdef FREECIV_IPV6_SUPPORT
1256 if (addr.saddr.sa_family == AF_INET6) {
1257 addr.saddr_in6.sin6_family = AF_INET6;
1258 addr.saddr_in6.sin6_port = htons(SERVER_LAN_PORT);
1259 addr.saddr_in6.sin6_addr = in6addr_any;
1260 } else
1261 #endif /* IPv6 support */
1262 if (addr.saddr.sa_family == AF_INET) {
1263 addr.saddr_in4.sin_family = AF_INET;
1264 addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT);
1265 addr.saddr_in4.sin_addr.s_addr = htonl(INADDR_ANY);
1266 } else {
1267 fc_assert(FALSE);
1269 log_error("Unsupported address family in server_open_socket()");
1272 if (bind(socklan, &addr.saddr, sockaddr_size(&addr)) < 0) {
1273 log_error("Announcement socket binding failed: %s", fc_strerror(fc_get_errno()));
1276 #ifndef FREECIV_IPV6_SUPPORT
1277 if (addr.saddr.sa_family == AF_INET) {
1278 #ifdef HAVE_INET_ATON
1279 inet_aton(group, &mreq4.imr_multiaddr);
1280 #else /* HAVE_INET_ATON */
1281 mreq4.imr_multiaddr.s_addr = inet_addr(group);
1282 #endif /* HAVE_INET_ATON */
1283 #else /* IPv6 support */
1284 if (addr.saddr.sa_family == AF_INET6) {
1285 inet_pton(AF_INET6, group, &mreq6.ipv6mr_multiaddr.s6_addr);
1286 mreq6.ipv6mr_interface = 0; /* TODO: Interface selection */
1287 if (setsockopt(socklan, IPPROTO_IPV6, FC_IPV6_ADD_MEMBERSHIP,
1288 (const char*)&mreq6, sizeof(mreq6)) < 0) {
1289 log_error("FC_IPV6_ADD_MEMBERSHIP (%s) failed: %s",
1290 group, fc_strerror(fc_get_errno()));
1292 } else if (addr.saddr.sa_family == AF_INET) {
1293 inet_pton(AF_INET, group, &mreq4.imr_multiaddr.s_addr);
1294 #endif /* IPv6 support */
1295 #ifdef HAVE_IP_MREQN
1296 mreq4.imr_address.s_addr = htonl(INADDR_ANY);
1297 mreq4.imr_ifindex = 0;
1298 #else
1299 mreq4.imr_interface.s_addr = htonl(INADDR_ANY);
1300 #endif
1302 if (setsockopt(socklan, IPPROTO_IP, IP_ADD_MEMBERSHIP,
1303 (const char*)&mreq4, sizeof(mreq4)) < 0) {
1304 log_error("IP_ADD_MEMBERSHIP (%s) failed: %s",
1305 group, fc_strerror(fc_get_errno()));
1307 } else {
1308 fc_assert(FALSE);
1310 log_error("Unsupported address family for broadcasting.");
1313 return 0;
1317 /********************************************************************
1318 Initialize connection related stuff. Attention: Logging is not
1319 available within this functions!
1320 ********************************************************************/
1321 void init_connections(void)
1323 int i;
1325 game.all_connections = conn_list_new();
1326 game.est_connections = conn_list_new();
1327 game.glob_observers = conn_list_new();
1329 for(i=0; i<MAX_NUM_CONNECTIONS; i++) {
1330 struct connection *pconn = &connections[i];
1331 pconn->used = FALSE;
1332 pconn->self = conn_list_new();
1333 conn_list_prepend(pconn->self, pconn);
1335 #if defined(__VMS)
1337 unsigned long status;
1338 $DESCRIPTOR (tt_desc, "SYS$INPUT");
1339 status = sys$assign(&tt_desc,&tt_chan,0,0);
1340 if (!$VMS_STATUS_SUCCESS(status)) lib$stop(status);
1342 #endif /* VMS */
1345 /**************************************************************************
1346 Starts processing of request packet from client.
1347 **************************************************************************/
1348 static void start_processing_request(struct connection *pconn,
1349 int request_id)
1351 fc_assert_ret(request_id);
1352 fc_assert_ret(pconn->server.currently_processed_request_id == 0);
1353 log_debug("start processing packet %d from connection %d",
1354 request_id, pconn->id);
1355 conn_compression_freeze(pconn);
1356 send_packet_processing_started(pconn);
1357 pconn->server.currently_processed_request_id = request_id;
1360 /**************************************************************************
1361 Finish processing of request packet from client.
1362 **************************************************************************/
1363 static void finish_processing_request(struct connection *pconn)
1365 if (!pconn || !pconn->used) {
1366 return;
1368 fc_assert_ret(pconn->server.currently_processed_request_id);
1369 log_debug("finish processing packet %d from connection %d",
1370 pconn->server.currently_processed_request_id, pconn->id);
1371 send_packet_processing_finished(pconn);
1372 pconn->server.currently_processed_request_id = 0;
1373 conn_compression_thaw(pconn);
1376 /****************************************************************************
1377 Ping a connection.
1378 ****************************************************************************/
1379 static void connection_ping(struct connection *pconn)
1381 struct timer *timer = timer_new(TIMER_USER, TIMER_ACTIVE);
1383 log_debug("sending ping to %s (open=%d)", conn_description(pconn),
1384 timer_list_size(pconn->server.ping_timers));
1385 timer_start(timer);
1386 timer_list_append(pconn->server.ping_timers, timer);
1387 send_packet_conn_ping(pconn);
1390 /**************************************************************************
1391 Handle response to ping.
1392 **************************************************************************/
1393 void handle_conn_pong(struct connection *pconn)
1395 struct timer *timer;
1397 if (timer_list_size(pconn->server.ping_timers) == 0) {
1398 log_error("got unexpected pong from %s", conn_description(pconn));
1399 return;
1402 timer = timer_list_front(pconn->server.ping_timers);
1403 pconn->ping_time = timer_read_seconds(timer);
1404 timer_list_pop_front(pconn->server.ping_timers);
1405 log_debug("got pong from %s (open=%d); ping time = %fs",
1406 conn_description(pconn),
1407 timer_list_size(pconn->server.ping_timers), pconn->ping_time);
1410 /**************************************************************************
1411 Handle client's regular hearbeat
1412 **************************************************************************/
1413 void handle_client_heartbeat(struct connection *pconn)
1415 log_debug("Received heartbeat");
1418 /**************************************************************************
1419 Send ping time info about all connections to all connections.
1420 **************************************************************************/
1421 static void send_ping_times_to_all(void)
1423 struct packet_conn_ping_info packet;
1424 int i;
1426 i = 0;
1427 conn_list_iterate(game.est_connections, pconn) {
1428 if (!pconn->used) {
1429 continue;
1431 fc_assert(i < ARRAY_SIZE(packet.conn_id));
1432 packet.conn_id[i] = pconn->id;
1433 packet.ping_time[i] = pconn->ping_time;
1434 i++;
1435 } conn_list_iterate_end;
1436 packet.connections = i;
1438 lsend_packet_conn_ping_info(game.est_connections, &packet);
1441 /********************************************************************
1442 Listen for UDP packets multicasted from clients requesting
1443 announcement of servers on the LAN.
1444 ********************************************************************/
1445 static void get_lanserver_announcement(void)
1447 char msgbuf[128];
1448 struct data_in din;
1449 int type;
1450 fd_set readfs, exceptfs;
1451 fc_timeval tv;
1453 if (srvarg.announce == ANNOUNCE_NONE) {
1454 return;
1457 FD_ZERO(&readfs);
1458 FD_ZERO(&exceptfs);
1459 FD_SET(socklan, &exceptfs);
1460 FD_SET(socklan, &readfs);
1462 tv.tv_sec = 0;
1463 tv.tv_usec = 0;
1465 while (fc_select(socklan + 1, &readfs, NULL, &exceptfs, &tv) == -1) {
1466 if (errno != EINTR) {
1467 log_error("select failed: %s", fc_strerror(fc_get_errno()));
1468 return;
1470 /* EINTR can happen sometimes, especially when compiling with -pg.
1471 * Generally we just want to run select again. */
1474 if (FD_ISSET(socklan, &readfs)) {
1475 if (0 < recvfrom(socklan, msgbuf, sizeof(msgbuf), 0, NULL, NULL)) {
1476 dio_input_init(&din, msgbuf, 1);
1477 dio_get_uint8(&din, &type);
1478 if (type == SERVER_LAN_VERSION) {
1479 log_debug("Received request for server LAN announcement.");
1480 send_lanserver_response();
1481 } else {
1482 log_debug("Received invalid request for server LAN announcement.");
1488 /********************************************************************
1489 This function broadcasts an UDP packet to clients with
1490 that requests information about the server state.
1491 ********************************************************************/
1492 static void send_lanserver_response(void)
1494 #ifndef FREECIV_HAVE_WINSOCK
1495 unsigned char buffer[MAX_LEN_PACKET];
1496 #else /* FREECIV_HAVE_WINSOCK */
1497 char buffer[MAX_LEN_PACKET];
1498 #endif /* FREECIV_HAVE_WINSOCK */
1499 char hostname[512];
1500 char port[256];
1501 char version[256];
1502 char players[256];
1503 int nhumans;
1504 char humans[256];
1505 char status[256];
1506 struct data_out dout;
1507 union fc_sockaddr addr;
1508 int socksend, setting = 1;
1509 const char *group;
1510 size_t size;
1511 #ifndef FREECIV_HAVE_WINSOCK
1512 unsigned char ttl;
1513 #endif
1515 /* Create a socket to broadcast to client. */
1516 if ((socksend = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1517 log_error("Lan response socket failed: %s", fc_strerror(fc_get_errno()));
1518 return;
1521 /* Set the UDP Multicast group IP address of the packet. */
1522 group = get_multicast_group(srvarg.announce == ANNOUNCE_IPV6);
1523 memset(&addr, 0, sizeof(addr));
1524 addr.saddr_in4.sin_family = AF_INET;
1525 addr.saddr_in4.sin_addr.s_addr = inet_addr(group);
1526 addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT + 1);
1528 /* this setsockopt call fails on Windows 98, so we stick with the default
1529 * value of 1 on Windows, which should be fine in most cases */
1530 #ifndef FREECIV_HAVE_WINSOCK
1531 /* Set the Time-to-Live field for the packet. */
1532 ttl = SERVER_LAN_TTL;
1533 if (setsockopt(socksend, IPPROTO_IP, IP_MULTICAST_TTL,
1534 (const char*)&ttl, sizeof(ttl))) {
1535 log_error("setsockopt failed: %s", fc_strerror(fc_get_errno()));
1536 return;
1538 #endif /* FREECIV_HAVE_WINSOCK */
1540 if (setsockopt(socksend, SOL_SOCKET, SO_BROADCAST,
1541 (const char*)&setting, sizeof(setting))) {
1542 log_error("Lan response setsockopt failed: %s", fc_strerror(fc_get_errno()));
1543 return;
1546 /* Create a description of server state to send to clients. */
1547 if (srvarg.identity_name[0] != '\0') {
1548 sz_strlcpy(hostname, srvarg.identity_name);
1549 } else if (fc_gethostname(hostname, sizeof(hostname)) != 0) {
1550 sz_strlcpy(hostname, "none");
1553 fc_snprintf(version, sizeof(version), "%d.%d.%d%s",
1554 MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, VERSION_LABEL);
1556 switch (server_state()) {
1557 case S_S_INITIAL:
1558 /* TRANS: Game state for local server */
1559 fc_snprintf(status, sizeof(status), _("Pregame"));
1560 break;
1561 case S_S_RUNNING:
1562 /* TRANS: Game state for local server */
1563 fc_snprintf(status, sizeof(status), _("Running"));
1564 break;
1565 case S_S_OVER:
1566 /* TRANS: Game state for local server */
1567 fc_snprintf(status, sizeof(status), _("Game over"));
1568 break;
1571 fc_snprintf(players, sizeof(players), "%d",
1572 normal_player_count());
1574 nhumans = 0;
1575 players_iterate(pplayer) {
1576 if (pplayer->is_alive && !pplayer->ai_controlled) {
1577 nhumans++;
1579 } players_iterate_end;
1580 fc_snprintf(humans, sizeof(humans), "%d", nhumans);
1582 fc_snprintf(port, sizeof(port), "%d",
1583 srvarg.port );
1585 dio_output_init(&dout, buffer, sizeof(buffer));
1586 dio_put_uint8(&dout, SERVER_LAN_VERSION);
1587 dio_put_string(&dout, hostname);
1588 dio_put_string(&dout, port);
1589 dio_put_string(&dout, version);
1590 dio_put_string(&dout, status);
1591 dio_put_string(&dout, players);
1592 dio_put_string(&dout, humans);
1593 dio_put_string(&dout, get_meta_message_string());
1594 size = dio_output_used(&dout);
1596 /* Sending packet to client with the information gathered above. */
1597 if (sendto(socksend, buffer, size, 0, &addr.saddr,
1598 sockaddr_size(&addr)) < 0) {
1599 log_error("landserver response sendto failed: %s",
1600 fc_strerror(fc_get_errno()));
1601 return;
1604 fc_closesocket(socksend);