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)
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 ***********************************************************************/
15 #include <fc_config.h>
18 #include "fc_prehdrs.h"
26 #ifdef FREECIV_HAVE_SYS_TYPES_H
27 #include <sys/types.h>
29 #ifdef HAVE_SYS_SOCKET_H
30 #include <sys/socket.h>
32 #ifdef HAVE_NETINET_IN_H
33 #include <netinet/in.h>
35 #ifdef HAVE_ARPA_INET_H
36 #include <arpa/inet.h>
44 #ifdef FREECIV_HAVE_LIBREADLINE
45 #include <readline/history.h>
46 #include <readline/readline.h>
48 #ifdef HAVE_SYS_SELECT_H
49 #include <sys/select.h>
51 #ifdef HAVE_SYS_TIME_H
62 #include "capability.h"
78 /* server/scripting */
79 #include "script_server.h"
84 #include "connecthand.h"
89 #include "stdinhand.h"
94 static struct connection connections
[MAX_NUM_CONNECTIONS
];
96 #ifdef GENERATING_MAC /* mac network globals */
97 TEndpointInfo serv_info
;
100 static int *listen_socks
;
101 static int listen_count
;
107 # define lib$stop LIB$STOP
108 # define sys$qiow SYS$QIOW
109 # define sys$assign SYS$ASSIGN
111 # include <descrip.h>
114 # include <starlet.h>
115 # include <lib$routines.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();
123 #define PROCESSING_TIME_STATISTICS 0
125 static int server_accept_connection(int sockfd
);
126 static void start_processing_request(struct connection
*pconn
,
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."));
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
)
180 handle_stdin_close(); /* maybe print an 'are you sure?' message? */
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
);
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
)
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
230 *****************************************************************************/
231 void close_connections_and_socket(void)
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
260 write_history(history_file
);
261 history_truncate_file(history_file
, HISTORY_LENGTH
);
266 #endif /* FREECIV_HAVE_LIBREADLINE */
268 send_server_info_to_metaserver(META_GOODBYE
);
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
;
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. */
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
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'
350 *****************************************************************************/
351 void flush_packets(void)
355 fd_set writefs
, exceptfs
;
362 tv
.tv_sec
= (game
.server
.netwait
- (time(NULL
) - start
));
369 FC_FD_ZERO(&writefs
);
370 FC_FD_ZERO(&exceptfs
);
373 for (i
= 0; i
< MAX_NUM_CONNECTIONS
; i
++) {
374 struct connection
*pconn
= &connections
[i
];
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) {
389 if (fc_select(max_desc
+ 1, NULL
, &writefs
, &exceptfs
, &tv
) <= 0) {
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"));
402 if(pconn
->send_buffer
&& pconn
->send_buffer
->ndata
> 0) {
403 if(FD_ISSET(pconn
->sock
, &writefs
)) {
404 flush_connection_send_buffer_all(pconn
);
406 cut_lagging_connection(pconn
);
415 struct packet_to_handle
{
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
;
443 while (get_packet(pconn
, &packet
)) {
446 #if PROCESSING_TIME_STATISTICS
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
);
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 */
475 connection_close_server(pconn
, _("rejected"));
479 #if PROCESSING_TIME_STATISTICS
480 timer_destroy(request_time
);
481 #endif /* PROCESSING_TIME_STATISTICS */
485 /*****************************************************************************
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)
499 fd_set readfs
, writefs
, exceptfs
;
501 #ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
507 #ifdef FREECIV_HAVE_LIBREADLINE
509 if (!no_input
&& !readline_initialized
) {
510 char *home_dir
= user_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
)) {
521 = fc_malloc(strlen(fc_dir
) + 1 + strlen(HISTORY_FILENAME
) + 1);
523 strcpy(history_file
, fc_dir
);
524 strcat(history_file
, "/");
525 strcat(history_file
, HISTORY_FILENAME
);
527 read_history(history_file
);
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 */
546 con_prompt_on(); /* accepting new input */
548 if (force_end_of_sniff
) {
549 force_end_of_sniff
= FALSE
;
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
;
562 if (conn_list_size(game
.est_connections
) > 0) {
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");
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. */
587 /* Do not restart before someone has connected and left again */
591 last_noplayers
= time(NULL
);
593 if (srvarg
.exit_on_end
) {
594 log_normal(_("Shutting down in %d seconds for lack of players."),
597 set_meta_message_string(N_("shutting down soon for lack of players"));
599 log_normal(_("Restarting in %d seconds for lack of players."),
602 set_meta_message_string(N_("restarting soon for lack of players"));
604 (void) send_server_info_to_metaserver(META_INFO
);
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
));
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) {
654 script_server_signal_emit("pulse", 0);
655 (void) send_server_info_to_metaserver(META_REFRESH
);
656 return S_E_END_OF_TURN_TIMEOUT
;
663 FC_FD_ZERO(&writefs
);
664 FC_FD_ZERO(&exceptfs
);
667 #ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
669 #else /* FREECIV_SOCKET_ZERO_NOT_STDIN */
673 #endif /* FREECIV_SOCKET_ZERO_NOT_STDIN */
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) {
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
)) {
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
);
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
)) {
737 if (ttchar
.numchars
) {
744 #ifndef FREECIV_SOCKET_ZERO_NOT_STDIN
745 really_close_connections();
747 #endif /* FREECIV_SOCKET_ZERO_NOT_STDIN */
753 for (i
= 0; i
< listen_count
; i
++) {
754 if (FD_ISSET(listen_socks
[i
], &exceptfs
)) {
759 if (excepting
) { /* handle Ctrl-Z suspend/resume */
762 for (i
= 0; i
< listen_count
; 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
];
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();
804 #else /* !FREECIV_HAVE_LIBREADLINE */
806 char *buffer
= NULL
; /* Must be NULL when calling getline() */
812 didget
= getline(&buffer
, &len
, stdin
);
814 buffer
[didget
-1] = '\0'; /* overwrite newline character */
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
);
824 buffer
[didget
] = '\0';
826 didget
= -1; /* error or end-of-file: closing stdin... */
828 #endif /* HAVE_GETLINE */
830 handle_stdin_close();
833 con_prompt_enter(); /* will need a new prompt, regardless */
836 buf_internal
= local_to_internal_string_malloc(buffer
);
837 handle_stdin_input(NULL
, buf_internal
);
841 #endif /* !FREECIV_HAVE_LIBREADLINE */
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
;
851 || pconn
->server
.is_closing
852 || !FD_ISSET(pconn
->sock
, &readfs
)) {
856 nb
= read_socket_data(pconn
->sock
, pconn
->buffer
);
858 /* We read packets; now handle them. */
859 incoming_client_packets(pconn
);
860 } else if (-2 == nb
) {
861 connection_close_server(pconn
, _("client disconnected"));
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
];
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
);
878 cut_lagging_connection(pconn
);
882 really_close_connections();
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
];
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
)) {
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
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. */
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
;
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()));
968 #ifdef FREECIV_IPV6_SUPPORT
969 if (fromend
.saddr
.sa_family
== AF_INET6
) {
970 inet_ntop(AF_INET6
, &fromend
.saddr_in6
.sin6_addr
,
972 } else if (fromend
.saddr
.sa_family
== AF_INET
) {
973 inet_ntop(AF_INET
, &fromend
.saddr_in4
.sin_addr
, dst
, sizeof(dst
));
977 log_error("Unsupported address family in server_accept_connection()");
981 #else /* IPv6 support */
982 dst
= inet_ntoa(fromend
.saddr_in4
.sin_addr
);
983 #endif /* IPv6 support */
985 if (0 != game
.server
.maxconnectionsperhost
) {
988 conn_list_iterate(game
.all_connections
, pconn
) {
989 if (0 != strcmp(dst
, pconn
->server
.ipaddr
)) {
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
);
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
;
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
1027 ********************************************************************/
1028 int server_make_connection(int new_sock
, const char *client_addr
, const char *client_ip
)
1030 struct timer
*timer
;
1033 fc_nonblock(new_sock
);
1035 for(i
=0; i
<MAX_NUM_CONNECTIONS
; i
++) {
1036 struct connection
*pconn
= &connections
[i
];
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
);
1072 timer_list_append(pconn
->server
.ping_timers
, timer
);
1077 log_error("maximum number of connections reached");
1078 fc_closesocket(new_sock
);
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
;
1093 struct ip_mreq mreq4
;
1095 const char *cause
, *group
;
1098 struct fc_sockaddr_list
*list
;
1101 union fc_sockaddr
*problematic
= NULL
;
1103 #ifdef FREECIV_IPV6_SUPPORT
1104 struct ipv6_mreq mreq6
;
1107 log_verbose("Server attempting to listen on %s:%d",
1108 srvarg
.bind_addr
? srvarg
.bind_addr
: "(any)",
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
);
1123 cause
= "internal"; /* If cause is not overwritten but gets printed... */
1126 /* Loop to create sockets, bind, listen. */
1127 listen_socks
= fc_calloc(name_count
, sizeof(listen_socks
[0]));
1130 fc_sockaddr_list_iterate(list
, paddr
) {
1131 /* Create socket for client connections. */
1132 s
= socket(paddr
->saddr
.sa_family
, SOCK_STREAM
, 0);
1134 /* Probably EAFNOSUPPORT or EPROTONOSUPPORT.
1135 * Kernel might have disabled AF_INET6. */
1136 eno
= fc_get_errno();
1138 problematic
= paddr
;
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
) {
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();
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. */
1181 /* Close all sockets. Another program might have bound to
1182 * one of our addresses, and might hijack some of our
1185 for (j
= 0; j
< listen_count
; j
++) {
1186 fc_closesocket(listen_socks
[j
]);
1193 if (listen(s
, MAX_NUM_CONNECTIONS
) == -1) {
1194 eno
= fc_get_errno();
1196 problematic
= paddr
;
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
;
1218 fc_sockaddr_list_destroy(list
);
1220 connections_set_close_callback(server_conn_close_callback
);
1222 if (srvarg
.announce
== ANNOUNCE_NONE
) {
1226 #ifdef FREECIV_IPV6_SUPPORT
1227 if (srvarg
.announce
== ANNOUNCE_IPV6
) {
1228 lan_family
= AF_INET6
;
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
;
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
);
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;
1299 mreq4
.imr_interface
.s_addr
= htonl(INADDR_ANY
);
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()));
1310 log_error("Unsupported address family for broadcasting.");
1317 /********************************************************************
1318 Initialize connection related stuff. Attention: Logging is not
1319 available within this functions!
1320 ********************************************************************/
1321 void init_connections(void)
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
);
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
);
1345 /**************************************************************************
1346 Starts processing of request packet from client.
1347 **************************************************************************/
1348 static void start_processing_request(struct connection
*pconn
,
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
) {
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 /****************************************************************************
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
));
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
));
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
;
1427 conn_list_iterate(game
.est_connections
, pconn
) {
1431 fc_assert(i
< ARRAY_SIZE(packet
.conn_id
));
1432 packet
.conn_id
[i
] = pconn
->id
;
1433 packet
.ping_time
[i
] = pconn
->ping_time
;
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)
1450 fd_set readfs
, exceptfs
;
1453 if (srvarg
.announce
== ANNOUNCE_NONE
) {
1459 FD_SET(socklan
, &exceptfs
);
1460 FD_SET(socklan
, &readfs
);
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()));
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();
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 */
1506 struct data_out dout
;
1507 union fc_sockaddr addr
;
1508 int socksend
, setting
= 1;
1511 #ifndef FREECIV_HAVE_WINSOCK
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()));
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()));
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()));
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()) {
1558 /* TRANS: Game state for local server */
1559 fc_snprintf(status
, sizeof(status
), _("Pregame"));
1562 /* TRANS: Game state for local server */
1563 fc_snprintf(status
, sizeof(status
), _("Running"));
1566 /* TRANS: Game state for local server */
1567 fc_snprintf(status
, sizeof(status
), _("Game over"));
1571 fc_snprintf(players
, sizeof(players
), "%d",
1572 normal_player_count());
1575 players_iterate(pplayer
) {
1576 if (pplayer
->is_alive
&& !pplayer
->ai_controlled
) {
1579 } players_iterate_end
;
1580 fc_snprintf(humans
, sizeof(humans
), "%d", nhumans
);
1582 fc_snprintf(port
, sizeof(port
), "%d",
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()));
1604 fc_closesocket(socksend
);