civ2civ3: improve README.civ2civ3 text.
[freeciv.git] / server / sernet.c
blobf69e2c2321db38deb85f3a623d6f5d2829e181c2
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->client_gui = GUI_STUB;
222 pconn->access_level = ALLOW_NONE;
223 connection_common_close(pconn);
225 send_updated_vote_totals(NULL);
228 /*****************************************************************************
229 Close all network stuff: connections, listening sockets, metaserver
230 connection...
231 *****************************************************************************/
232 void close_connections_and_socket(void)
234 int i;
236 lsend_packet_server_shutdown(game.all_connections);
238 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
239 if (connections[i].used) {
240 close_connection(&connections[i]);
242 conn_list_destroy(connections[i].self);
245 /* Remove the game connection lists and make sure they are empty. */
246 conn_list_destroy(game.glob_observers);
247 conn_list_destroy(game.all_connections);
248 conn_list_destroy(game.est_connections);
250 for (i = 0; i < listen_count; i++) {
251 fc_closesocket(listen_socks[i]);
253 FC_FREE(listen_socks);
255 if (srvarg.announce != ANNOUNCE_NONE) {
256 fc_closesocket(socklan);
259 #ifdef FREECIV_HAVE_LIBREADLINE
260 if (history_file) {
261 write_history(history_file);
262 history_truncate_file(history_file, HISTORY_LENGTH);
263 free(history_file);
264 history_file = NULL;
265 clear_history();
267 #endif /* FREECIV_HAVE_LIBREADLINE */
269 send_server_info_to_metaserver(META_GOODBYE);
270 server_close_meta();
272 packets_deinit();
273 fc_shutdown_network();
276 /****************************************************************************
277 Now really close connections marked as 'is_closing'.
278 Do this here to avoid recursive sending.
279 ****************************************************************************/
280 static void really_close_connections(void)
282 struct connection *closing[MAX_NUM_CONNECTIONS];
283 struct connection *pconn;
284 int i, num;
286 do {
287 num = 0;
289 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
290 pconn = connections + i;
291 if (pconn->used && pconn->server.is_closing) {
292 closing[num++] = pconn;
293 /* Remove closing connections from the lists (hard detach)
294 * to avoid sending to closing connections. */
295 conn_list_remove(game.glob_observers, pconn);
296 conn_list_remove(game.est_connections, pconn);
297 conn_list_remove(game.all_connections, pconn);
298 if (NULL != conn_get_player(pconn)) {
299 conn_list_remove(conn_get_player(pconn)->connections, pconn);
304 for (i = 0; i < num; i++) {
305 /* Now really close them. */
306 pconn = closing[i];
307 lost_connection_to_client(pconn);
308 close_connection(pconn);
310 } while (0 < num); /* May some errors occurred, let's check. */
313 /****************************************************************************
314 Break a client connection. You should almost always use
315 connection_close_server() instead of calling this function directly.
316 ****************************************************************************/
317 static void server_conn_close_callback(struct connection *pconn)
319 /* Do as little as possible here to avoid recursive evil. */
320 pconn->server.is_closing = TRUE;
323 /****************************************************************************
324 If a connection lags too much this function is called and we try to cut
326 ****************************************************************************/
327 static void cut_lagging_connection(struct connection *pconn)
329 if (!pconn->server.is_closing
330 && game.server.tcptimeout != 0
331 && pconn->last_write
332 && conn_list_size(game.all_connections) > 1
333 && pconn->access_level != ALLOW_HACK
334 && timer_read_seconds(pconn->last_write) > game.server.tcptimeout) {
335 /* Cut the connections to players who lag too much. This
336 * usually happens because client animation slows the client
337 * too much and it can't keep up with the server. We don't
338 * cut HACK connections, or cut in single-player games, since
339 * it wouldn't help the game progress. For other connections
340 * the best thing to do when they lag too much is to be
341 * disconnected and reconnect. */
342 log_verbose("connection (%s) cut due to lagging player",
343 conn_description(pconn));
344 connection_close_server(pconn, _("lagging connection"));
348 /****************************************************************************
349 Attempt to flush all information in the send buffers for upto 'netwait'
350 seconds.
351 *****************************************************************************/
352 void flush_packets(void)
354 int i;
355 int max_desc;
356 fd_set writefs, exceptfs;
357 fc_timeval tv;
358 time_t start;
360 (void) time(&start);
362 for (;;) {
363 tv.tv_sec = (game.server.netwait - (time(NULL) - start));
364 tv.tv_usec = 0;
366 if (tv.tv_sec < 0) {
367 return;
370 FC_FD_ZERO(&writefs);
371 FC_FD_ZERO(&exceptfs);
372 max_desc = -1;
374 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
375 struct connection *pconn = &connections[i];
377 if (pconn->used
378 && !pconn->server.is_closing
379 && 0 < pconn->send_buffer->ndata) {
380 FD_SET(pconn->sock, &writefs);
381 FD_SET(pconn->sock, &exceptfs);
382 max_desc = MAX(pconn->sock, max_desc);
386 if (max_desc == -1) {
387 return;
390 if (fc_select(max_desc + 1, NULL, &writefs, &exceptfs, &tv) <= 0) {
391 return;
394 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) { /* check for freaky players */
395 struct connection *pconn = &connections[i];
397 if (pconn->used && !pconn->server.is_closing) {
398 if (FD_ISSET(pconn->sock, &exceptfs)) {
399 log_verbose("connection (%s) cut due to exception data",
400 conn_description(pconn));
401 connection_close_server(pconn, _("network exception"));
402 } else {
403 if (pconn->send_buffer && pconn->send_buffer->ndata > 0) {
404 if (FD_ISSET(pconn->sock, &writefs)) {
405 flush_connection_send_buffer_all(pconn);
406 } else {
407 cut_lagging_connection(pconn);
416 struct packet_to_handle {
417 void *data;
418 enum packet_type type;
421 /*****************************************************************************
422 Simplify a loop by wrapping get_packet_from_connection.
423 *****************************************************************************/
424 static bool get_packet(struct connection *pconn,
425 struct packet_to_handle *ppacket)
427 ppacket->data = get_packet_from_connection(pconn, &ppacket->type);
429 return NULL != ppacket->data;
432 /*****************************************************************************
433 Handle all incoming packets on a client connection.
434 Precondition - we have read_socket_data.
435 Postcondition - there are no more packets to handle on this connection.
436 *****************************************************************************/
437 static void incoming_client_packets(struct connection *pconn)
439 struct packet_to_handle packet;
440 #if PROCESSING_TIME_STATISTICS
441 struct timer *request_time = NULL;
442 #endif
444 while (get_packet(pconn, &packet)) {
445 bool command_ok;
447 #if PROCESSING_TIME_STATISTICS
448 int request_id;
450 request_time = timer_renew(request_time, TIMER_USER, TIMER_ACTIVE);
451 timer_start(request_time);
452 #endif /* PROCESSING_TIME_STATISTICS */
454 pconn->server.last_request_id_seen
455 = get_next_request_id(pconn->server.last_request_id_seen);
457 #if PROCESSING_TIME_STATISTICS
458 request_id = pconn->server.last_request_id_seen;
459 #endif /* PROCESSING_TIME_STATISTICS */
461 connection_do_buffer(pconn);
462 start_processing_request(pconn, pconn->server.last_request_id_seen);
464 command_ok = server_packet_input(pconn, packet.data, packet.type);
465 free(packet.data);
467 finish_processing_request(pconn);
468 connection_do_unbuffer(pconn);
470 #if PROCESSING_TIME_STATISTICS
471 log_verbose("processed request %d in %gms", request_id,
472 timer_read_seconds(request_time) * 1000.0);
473 #endif /* PROCESSING_TIME_STATISTICS */
475 if (!command_ok) {
476 connection_close_server(pconn, _("rejected"));
480 #if PROCESSING_TIME_STATISTICS
481 timer_destroy(request_time);
482 #endif /* PROCESSING_TIME_STATISTICS */
486 /*****************************************************************************
487 Get and handle:
488 - new connections,
489 - input from connections,
490 - input from server operator in stdin
492 This function also handles prompt printing, via the con_prompt_*
493 functions. That is, other functions should not need to do so. --dwp
494 *****************************************************************************/
495 enum server_events server_sniff_all_input(void)
497 int i, s;
498 int max_desc;
499 bool excepting;
500 fd_set readfs, writefs, exceptfs;
501 fc_timeval tv;
502 #ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
503 char *bufptr;
504 #endif
506 con_prompt_init();
508 #ifdef FREECIV_HAVE_LIBREADLINE
510 if (!no_input && !readline_initialized) {
511 char *storage_dir = freeciv_storage_dir();
513 if (storage_dir != NULL) {
514 int fcdl = strlen(storage_dir) + 1;
515 char *fc_dir = fc_malloc(fcdl);
517 if (fc_dir != NULL) {
518 fc_snprintf(fc_dir, fcdl, "%s", storage_dir);
520 if (make_dir(fc_dir)) {
521 history_file
522 = fc_malloc(strlen(fc_dir) + 1 + strlen(HISTORY_FILENAME) + 1);
523 if (history_file) {
524 strcpy(history_file, fc_dir);
525 strcat(history_file, "/");
526 strcat(history_file, HISTORY_FILENAME);
527 using_history();
528 read_history(history_file);
531 FC_FREE(fc_dir);
535 rl_initialize();
536 rl_callback_handler_install((char *) "> ",
537 handle_readline_input_callback);
538 rl_attempted_completion_function = freeciv_completion;
540 readline_initialized = TRUE;
541 atexit(rl_callback_handler_remove);
544 #endif /* FREECIV_HAVE_LIBREADLINE */
546 while (TRUE) {
547 con_prompt_on(); /* accepting new input */
549 if (force_end_of_sniff) {
550 force_end_of_sniff = FALSE;
551 con_prompt_off();
552 return S_E_FORCE_END_OF_SNIFF;
555 get_lanserver_announcement();
557 /* end server if no players for 'srvarg.quitidle' seconds,
558 * but only if at least one player has previously connected. */
559 if (srvarg.quitidle != 0) {
560 static time_t last_noplayers;
561 static bool conns;
563 if (conn_list_size(game.est_connections) > 0) {
564 conns = TRUE;
566 if (conns && conn_list_size(game.est_connections) == 0) {
567 if (last_noplayers != 0) {
568 if (time(NULL) > last_noplayers + srvarg.quitidle) {
569 save_game_auto("Lost all connections", AS_QUITIDLE);
571 if (srvarg.exit_on_end) {
572 log_normal(_("Shutting down for lack of players."));
573 set_meta_message_string("shutting down for lack of players");
574 } else {
575 log_normal(_("Restarting for lack of players."));
576 set_meta_message_string("restarting for lack of players");
578 (void) send_server_info_to_metaserver(META_INFO);
580 set_server_state(S_S_OVER);
581 force_end_of_sniff = TRUE;
583 if (srvarg.exit_on_end) {
584 /* No need for anything more; just quit. */
585 server_quit();
588 /* Do not restart before someone has connected and left again */
589 conns = FALSE;
591 } else {
592 last_noplayers = time(NULL);
594 if (srvarg.exit_on_end) {
595 log_normal(_("Shutting down in %d seconds for lack of players."),
596 srvarg.quitidle);
598 set_meta_message_string(N_("shutting down soon for lack of players"));
599 } else {
600 log_normal(_("Restarting in %d seconds for lack of players."),
601 srvarg.quitidle);
603 set_meta_message_string(N_("restarting soon for lack of players"));
605 (void) send_server_info_to_metaserver(META_INFO);
607 } else {
608 last_noplayers = 0;
612 /* Pinging around for statistics */
613 if (time(NULL) > (game.server.last_ping + game.server.pingtime)) {
614 /* send data about the previous run */
615 send_ping_times_to_all();
617 conn_list_iterate(game.all_connections, pconn) {
618 if ((!pconn->server.is_closing
619 && 0 < timer_list_size(pconn->server.ping_timers)
620 && timer_read_seconds(timer_list_front
621 (pconn->server.ping_timers))
622 > game.server.pingtimeout)
623 || pconn->ping_time > game.server.pingtimeout) {
624 /* cut mute players, except for hack-level ones */
625 if (pconn->access_level == ALLOW_HACK) {
626 log_verbose("connection (%s) [hack-level] ping timeout ignored",
627 conn_description(pconn));
628 } else {
629 log_verbose("connection (%s) cut due to ping timeout",
630 conn_description(pconn));
631 connection_close_server(pconn, _("ping timeout"));
633 } else if (pconn->established) {
634 /* We don't send ping to connection not established, because
635 * we wouldn't be able to handle asynchronous ping/pong with
636 * different packet header size. */
637 connection_ping(pconn);
639 } conn_list_iterate_end;
640 game.server.last_ping = time(NULL);
643 /* if we've waited long enough after a failure, respond to the client */
644 conn_list_iterate(game.all_connections, pconn) {
645 if (srvarg.auth_enabled
646 && !pconn->server.is_closing
647 && pconn->server.status != AS_ESTABLISHED) {
648 auth_process_status(pconn);
650 } conn_list_iterate_end
652 /* Don't wait if timeout == -1 (i.e. on auto games) */
653 if (S_S_RUNNING == server_state() && game.info.timeout == -1) {
654 call_ai_refresh();
655 script_server_signal_emit("pulse", 0);
656 (void) send_server_info_to_metaserver(META_REFRESH);
657 return S_E_END_OF_TURN_TIMEOUT;
660 tv.tv_sec = 1;
661 tv.tv_usec = 0;
663 FC_FD_ZERO(&readfs);
664 FC_FD_ZERO(&writefs);
665 FC_FD_ZERO(&exceptfs);
667 if (!no_input) {
668 #ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
669 fc_init_console();
670 #else /* FREECIV_SOCKET_ZERO_NOT_STDIN */
671 # if !defined(__VMS)
672 FD_SET(0, &readfs);
673 # endif /* VMS */
674 #endif /* FREECIV_SOCKET_ZERO_NOT_STDIN */
677 max_desc = 0;
678 for (i = 0; i < listen_count; i++) {
679 FD_SET(listen_socks[i], &readfs);
680 FD_SET(listen_socks[i], &exceptfs);
681 max_desc = MAX(max_desc, listen_socks[i]);
684 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
685 struct connection *pconn = connections + i;
687 if (pconn->used && !pconn->server.is_closing) {
688 FD_SET(pconn->sock, &readfs);
689 if (0 < pconn->send_buffer->ndata) {
690 FD_SET(pconn->sock, &writefs);
692 FD_SET(pconn->sock, &exceptfs);
693 max_desc = MAX(pconn->sock, max_desc);
696 con_prompt_off(); /* output doesn't generate a new prompt */
698 if (fc_select(max_desc + 1, &readfs, &writefs, &exceptfs, &tv) == 0) {
699 /* timeout */
700 call_ai_refresh();
701 script_server_signal_emit("pulse", 0);
702 (void) send_server_info_to_metaserver(META_REFRESH);
703 if (current_turn_timeout() > 0
704 && S_S_RUNNING == server_state()
705 && game.server.phase_timer
706 && (timer_read_seconds(game.server.phase_timer)
707 > game.tinfo.seconds_to_phasedone)) {
708 con_prompt_off();
709 return S_E_END_OF_TURN_TIMEOUT;
711 if ((game.server.autosaves & (1 << AS_TIMER))
712 && S_S_RUNNING == server_state()
713 && (timer_read_seconds(game.server.save_timer)
714 >= game.server.save_frequency * 60)) {
715 save_game_auto("Timer", AS_TIMER);
716 game.server.save_timer = timer_renew(game.server.save_timer,
717 TIMER_USER, TIMER_ACTIVE);
718 timer_start(game.server.save_timer);
721 if (!no_input) {
722 #if defined(__VMS)
724 struct {
725 short numchars;
726 char firstchar;
727 char reserved;
728 int reserved2;
729 } ttchar;
730 unsigned long status;
732 status = sys$qiow(EFN$C_ENF, tt_chan,
733 IO$_SENSEMODE | IO$M_TYPEAHDCNT, 0, 0, 0,
734 &ttchar, sizeof(ttchar), 0, 0, 0, 0);
735 if (!$VMS_STATUS_SUCCESS(status)) {
736 lib$stop(status);
738 if (ttchar.numchars) {
739 FD_SET(0, &readfs);
740 } else {
741 continue;
744 #else /* !__VMS */
745 #ifndef FREECIV_SOCKET_ZERO_NOT_STDIN
746 really_close_connections();
747 continue;
748 #endif /* FREECIV_SOCKET_ZERO_NOT_STDIN */
749 #endif /* !__VMS */
753 excepting = FALSE;
754 for (i = 0; i < listen_count; i++) {
755 if (FD_ISSET(listen_socks[i], &exceptfs)) {
756 excepting = TRUE;
757 break;
760 if (excepting) { /* handle Ctrl-Z suspend/resume */
761 continue;
763 for (i = 0; i < listen_count; i++) {
764 s = listen_socks[i];
765 if (FD_ISSET(s, &readfs)) { /* new players connects */
766 log_verbose("got new connection");
767 if (-1 == server_accept_connection(s)) {
768 /* There will be a log_error() message from
769 * server_accept_connection() if something
770 * goes wrong, so no need to make another
771 * error-level message here. */
772 log_verbose("failed accepting connection");
776 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
777 /* check for freaky players */
778 struct connection *pconn = &connections[i];
780 if (pconn->used
781 && !pconn->server.is_closing
782 && FD_ISSET(pconn->sock, &exceptfs)) {
783 log_verbose("connection (%s) cut due to exception data",
784 conn_description(pconn));
785 connection_close_server(pconn, _("network exception"));
788 #ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
789 if (!no_input && (bufptr = fc_read_console())) {
790 char *bufptr_internal = local_to_internal_string_malloc(bufptr);
792 con_prompt_enter(); /* will need a new prompt, regardless */
793 handle_stdin_input(NULL, bufptr_internal);
794 free(bufptr_internal);
796 #else /* !FREECIV_SOCKET_ZERO_NOT_STDIN */
797 if (!no_input && FD_ISSET(0, &readfs)) { /* input from server operator */
798 #ifdef FREECIV_HAVE_LIBREADLINE
799 rl_callback_read_char();
800 if (readline_handled_input) {
801 readline_handled_input = FALSE;
802 con_prompt_enter_clear();
804 continue;
805 #else /* !FREECIV_HAVE_LIBREADLINE */
806 ssize_t didget;
807 char *buffer = NULL; /* Must be NULL when calling getline() */
808 char *buf_internal;
810 #ifdef HAVE_GETLINE
811 size_t len = 0;
813 didget = getline(&buffer, &len, stdin);
814 if (didget >= 1) {
815 buffer[didget-1] = '\0'; /* overwrite newline character */
816 didget--;
817 log_debug("Got line: \"%s\" (%ld, %ld)", buffer,
818 (long int) didget, (long int) len);
820 #else /* HAVE_GETLINE */
821 buffer = malloc(BUF_SIZE + 1);
823 didget = read(0, buffer, BUF_SIZE);
824 if (didget > 0) {
825 buffer[didget] = '\0';
826 } else {
827 didget = -1; /* error or end-of-file: closing stdin... */
829 #endif /* HAVE_GETLINE */
830 if (didget < 0) {
831 handle_stdin_close();
834 con_prompt_enter(); /* will need a new prompt, regardless */
836 if (didget >= 0) {
837 buf_internal = local_to_internal_string_malloc(buffer);
838 handle_stdin_input(NULL, buf_internal);
839 free(buf_internal);
841 free(buffer);
842 #endif /* !FREECIV_HAVE_LIBREADLINE */
843 } else
844 #endif /* !FREECIV_SOCKET_ZERO_NOT_STDIN */
846 { /* input from a player */
847 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
848 struct connection *pconn = connections + i;
849 int nb;
851 if (!pconn->used
852 || pconn->server.is_closing
853 || !FD_ISSET(pconn->sock, &readfs)) {
854 continue;
857 nb = read_socket_data(pconn->sock, pconn->buffer);
858 if (0 <= nb) {
859 /* We read packets; now handle them. */
860 incoming_client_packets(pconn);
861 } else if (-2 == nb) {
862 connection_close_server(pconn, _("client disconnected"));
863 } else {
864 /* Read failure; the connection is closed. */
865 connection_close_server(pconn, _("read error"));
869 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
870 struct connection *pconn = &connections[i];
872 if (pconn->used
873 && !pconn->server.is_closing
874 && pconn->send_buffer
875 && pconn->send_buffer->ndata > 0) {
876 if (FD_ISSET(pconn->sock, &writefs)) {
877 flush_connection_send_buffer_all(pconn);
878 } else {
879 cut_lagging_connection(pconn);
883 really_close_connections();
884 break;
887 con_prompt_off();
889 call_ai_refresh();
890 script_server_signal_emit("pulse", 0);
892 if (current_turn_timeout() > 0
893 && S_S_RUNNING == server_state()
894 && game.server.phase_timer
895 && (timer_read_seconds(game.server.phase_timer)
896 > game.tinfo.seconds_to_phasedone)) {
897 return S_E_END_OF_TURN_TIMEOUT;
899 if ((game.server.autosaves & (1 << AS_TIMER))
900 && S_S_RUNNING == server_state()
901 && (timer_read_seconds(game.server.save_timer)
902 >= game.server.save_frequency * 60)) {
903 save_game_auto("Timer", AS_TIMER);
904 game.server.save_timer = timer_renew(game.server.save_timer,
905 TIMER_USER, TIMER_ACTIVE);
906 timer_start(game.server.save_timer);
909 return S_E_OTHERWISE;
912 /********************************************************************
913 Make up a name for the connection, before we get any data from
914 it to use as a sensible name. Name will be 'c' + integer,
915 guaranteed not to be the same as any other connection name,
916 nor player name nor user name, nor connection id (avoid possible
917 confusions). Returns pointer to static buffer, and fills in
918 (*id) with chosen value.
919 ********************************************************************/
920 static const char *makeup_connection_name(int *id)
922 static unsigned short i = 0;
923 static char name[MAX_LEN_NAME];
925 for (;;) {
926 if (i == (unsigned short) - 1) {
927 /* don't use 0 */
928 i++;
930 fc_snprintf(name, sizeof(name), "c%u", (unsigned int)++i);
931 if (NULL == player_by_name(name)
932 && NULL == player_by_user(name)
933 && NULL == conn_by_number(i)
934 && NULL == conn_by_user(name)) {
935 *id = i;
936 return name;
941 /********************************************************************
942 Server accepts connection from client:
943 Low level socket stuff, and basic-initialize the connection struct.
944 Returns 0 on success, -1 on failure (bad accept(), or too many
945 connections).
946 ********************************************************************/
947 static int server_accept_connection(int sockfd)
949 /* This used to have size_t for some platforms. If this is necessary
950 * it should be done with a configure check not a platform check. */
951 socklen_t fromlen;
953 int new_sock;
954 union fc_sockaddr fromend;
955 bool nameinfo = FALSE;
956 #ifdef FREECIV_IPV6_SUPPORT
957 char host[NI_MAXHOST], service[NI_MAXSERV];
958 char dst[INET6_ADDRSTRLEN];
959 #else /* IPv6 support */
960 struct hostent *from;
961 const char *host = NULL;
962 const char *dst;
963 #endif /* IPv6 support */
965 fromlen = sizeof(fromend);
967 if ((new_sock = accept(sockfd, &fromend.saddr, &fromlen)) == -1) {
968 log_error("accept failed: %s", fc_strerror(fc_get_errno()));
969 return -1;
972 #ifdef FREECIV_IPV6_SUPPORT
973 if (fromend.saddr.sa_family == AF_INET6) {
974 inet_ntop(AF_INET6, &fromend.saddr_in6.sin6_addr,
975 dst, sizeof(dst));
976 } else if (fromend.saddr.sa_family == AF_INET) {
977 inet_ntop(AF_INET, &fromend.saddr_in4.sin_addr, dst, sizeof(dst));
978 } else {
979 fc_assert(FALSE);
981 log_error("Unsupported address family in server_accept_connection()");
983 return -1;
985 #else /* IPv6 support */
986 dst = inet_ntoa(fromend.saddr_in4.sin_addr);
987 #endif /* IPv6 support */
989 if (0 != game.server.maxconnectionsperhost) {
990 int count = 0;
992 conn_list_iterate(game.all_connections, pconn) {
993 if (0 != strcmp(dst, pconn->server.ipaddr)) {
994 continue;
996 if (++count >= game.server.maxconnectionsperhost) {
997 log_verbose("Rejecting new connection from %s: maximum number of "
998 "connections for this address exceeded (%d).",
999 dst, game.server.maxconnectionsperhost);
1001 /* Disconnect the accepted socket. */
1002 fc_closesocket(new_sock);
1004 return -1;
1006 } conn_list_iterate_end;
1009 #ifdef FREECIV_IPV6_SUPPORT
1010 nameinfo = (0 == getnameinfo(&fromend.saddr, fromlen, host, NI_MAXHOST,
1011 service, NI_MAXSERV, NI_NUMERICSERV)
1012 && '\0' != host[0]);
1013 #else /* IPv6 support */
1014 from = gethostbyaddr((char *) &fromend.saddr_in4.sin_addr,
1015 sizeof(fromend.saddr_in4.sin_addr), AF_INET);
1016 if (NULL != from && '\0' != from->h_name[0]) {
1017 host = from->h_name;
1018 nameinfo = TRUE;
1020 #endif /* IPv6 support */
1022 return server_make_connection(new_sock,
1023 (nameinfo ? host : dst), dst);
1026 /********************************************************************
1027 Server accepts connection from client:
1028 Low level socket stuff, and basic-initialize the connection struct.
1029 Returns 0 on success, -1 on failure (bad accept(), or too many
1030 connections).
1031 ********************************************************************/
1032 int server_make_connection(int new_sock, const char *client_addr,
1033 const char *client_ip)
1035 struct timer *timer;
1036 int i;
1038 fc_nonblock(new_sock);
1040 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
1041 struct connection *pconn = &connections[i];
1043 if (!pconn->used) {
1044 connection_common_init(pconn);
1045 pconn->sock = new_sock;
1046 pconn->observer = FALSE;
1047 pconn->playing = NULL;
1048 pconn->capability[0] = '\0';
1049 pconn->access_level = access_level_for_next_connection();
1050 pconn->notify_of_writable_data = NULL;
1051 pconn->server.currently_processed_request_id = 0;
1052 pconn->server.last_request_id_seen = 0;
1053 pconn->server.auth_tries = 0;
1054 pconn->server.auth_settime = 0;
1055 pconn->server.status = AS_NOT_ESTABLISHED;
1056 pconn->server.ping_timers = timer_list_new_full(timer_destroy);
1057 pconn->server.granted_access_level = pconn->access_level;
1058 pconn->server.ignore_list =
1059 conn_pattern_list_new_full(conn_pattern_destroy);
1060 pconn->server.is_closing = FALSE;
1061 pconn->ping_time = -1.0;
1062 pconn->incoming_packet_notify = NULL;
1063 pconn->outgoing_packet_notify = NULL;
1065 sz_strlcpy(pconn->username, makeup_connection_name(&pconn->id));
1066 sz_strlcpy(pconn->addr, client_addr);
1067 sz_strlcpy(pconn->server.ipaddr, client_ip);
1069 conn_list_append(game.all_connections, pconn);
1071 log_verbose("connection (%s) from %s (%s)",
1072 pconn->username, pconn->addr, pconn->server.ipaddr);
1073 /* Give a ping timeout to send the PACKET_SERVER_JOIN_REQ, or close
1074 * the mute connection. This timer will be canceled into
1075 * connecthand.c:handle_login_request(). */
1076 timer = timer_new(TIMER_USER, TIMER_ACTIVE);
1077 timer_start(timer);
1078 timer_list_append(pconn->server.ping_timers, timer);
1079 return 0;
1083 log_error("maximum number of connections reached");
1084 fc_closesocket(new_sock);
1085 return -1;
1088 /********************************************************************
1089 Open server socket to be used to accept client connections
1090 and open a server socket for server LAN announcements.
1091 ********************************************************************/
1092 int server_open_socket(void)
1094 /* setup socket address */
1095 union fc_sockaddr addr;
1096 #ifdef HAVE_IP_MREQN
1097 struct ip_mreqn mreq4;
1098 #else
1099 struct ip_mreq mreq4;
1100 #endif
1101 const char *cause, *group;
1102 int j, on, s;
1103 int lan_family;
1104 struct fc_sockaddr_list *list;
1105 int name_count;
1106 fc_errno eno = 0;
1107 union fc_sockaddr *problematic = NULL;
1109 #ifdef FREECIV_IPV6_SUPPORT
1110 struct ipv6_mreq mreq6;
1111 #endif
1113 log_verbose("Server attempting to listen on %s:%d",
1114 srvarg.bind_addr ? srvarg.bind_addr : "(any)",
1115 srvarg.port);
1117 /* Any supported family will do */
1118 list = net_lookup_service(srvarg.bind_addr, srvarg.port, FC_ADDR_ANY);
1120 name_count = fc_sockaddr_list_size(list);
1122 /* Lookup addresses to bind. */
1123 if (name_count <= 0) {
1124 log_fatal(_("Server: bad address: <%s:%d>."),
1125 srvarg.bind_addr ? srvarg.bind_addr : "(none)", srvarg.port);
1126 exit(EXIT_FAILURE);
1129 cause = "internal"; /* If cause is not overwritten but gets printed... */
1130 on = 1;
1132 /* Loop to create sockets, bind, listen. */
1133 listen_socks = fc_calloc(name_count, sizeof(listen_socks[0]));
1134 listen_count = 0;
1136 fc_sockaddr_list_iterate(list, paddr) {
1137 /* Create socket for client connections. */
1138 s = socket(paddr->saddr.sa_family, SOCK_STREAM, 0);
1139 if (s == -1) {
1140 /* Probably EAFNOSUPPORT or EPROTONOSUPPORT.
1141 * Kernel might have disabled AF_INET6. */
1142 eno = fc_get_errno();
1143 cause = "socket";
1144 problematic = paddr;
1145 continue;
1148 #ifndef FREECIV_HAVE_WINSOCK
1149 /* SO_REUSEADDR considered harmful on Win, necessary otherwise */
1150 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1151 (char *)&on, sizeof(on)) == -1) {
1152 log_error("setsockopt SO_REUSEADDR failed: %s",
1153 fc_strerror(fc_get_errno()));
1154 sockaddr_debug(paddr, LOG_NORMAL);
1156 #endif /* FREECIV_HAVE_WINSOCK */
1158 /* AF_INET6 sockets should use IPv6 only,
1159 * without stealing IPv4 from AF_INET sockets. */
1160 #ifdef FREECIV_IPV6_SUPPORT
1161 if (paddr->saddr.sa_family == AF_INET6) {
1162 #ifdef IPV6_V6ONLY
1163 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
1164 (char *)&on, sizeof(on)) == -1) {
1165 log_error("setsockopt IPV6_V6ONLY failed: %s",
1166 fc_strerror(fc_get_errno()));
1167 sockaddr_debug(paddr, LOG_DEBUG);
1169 #endif /* IPV6_V6ONLY */
1171 #endif /* IPv6 support */
1173 if (bind(s, &paddr->saddr, sockaddr_size(paddr)) == -1) {
1174 eno = fc_get_errno();
1175 cause = "bind";
1176 problematic = paddr;
1178 if (eno == EADDRNOTAVAIL) {
1179 /* Close only this socket. This address is not available.
1180 * This can happen with the IPv6 wildcard address if this
1181 * machine has no IPv6 interfaces. */
1182 /* If you change this logic, be sure to make clientside checking
1183 * of acceptable port to match. */
1184 fc_closesocket(s);
1185 continue;
1186 } else {
1187 /* Close all sockets. Another program might have bound to
1188 * one of our addresses, and might hijack some of our
1189 * connections. */
1190 fc_closesocket(s);
1191 for (j = 0; j < listen_count; j++) {
1192 fc_closesocket(listen_socks[j]);
1194 listen_count = 0;
1195 break;
1199 if (listen(s, MAX_NUM_CONNECTIONS) == -1) {
1200 eno = fc_get_errno();
1201 cause = "listen";
1202 problematic = paddr;
1203 fc_closesocket(s);
1204 continue;
1207 listen_socks[listen_count++] = s;
1208 } fc_sockaddr_list_iterate_end;
1210 if (listen_count == 0) {
1211 log_fatal("%s failure: %s (%d failed)", cause, fc_strerror(eno), name_count);
1212 if (problematic != NULL) {
1213 sockaddr_debug(problematic, LOG_NORMAL);
1215 fc_sockaddr_list_iterate(list, paddr) {
1216 /* Do not list already logged 'problematic' again */
1217 if (paddr != problematic) {
1218 sockaddr_debug(paddr, LOG_DEBUG);
1220 } fc_sockaddr_list_iterate_end;
1221 exit(EXIT_FAILURE);
1224 fc_sockaddr_list_destroy(list);
1226 connections_set_close_callback(server_conn_close_callback);
1228 if (srvarg.announce == ANNOUNCE_NONE) {
1229 return 0;
1232 #ifdef FREECIV_IPV6_SUPPORT
1233 if (srvarg.announce == ANNOUNCE_IPV6) {
1234 lan_family = AF_INET6;
1235 } else
1236 #endif /* IPV6 support */
1238 lan_family = AF_INET;
1241 /* Create socket for server LAN announcements */
1242 if ((socklan = socket(lan_family, SOCK_DGRAM, 0)) < 0) {
1243 log_error("Announcement socket failed: %s", fc_strerror(fc_get_errno()));
1244 return 0; /* FIXME: Should this cause hard error as exit(EXIT_FAILURE).
1245 * It's failure to do as commandline parameters requested after all */
1248 if (setsockopt(socklan, SOL_SOCKET, SO_REUSEADDR,
1249 (char *)&on, sizeof(on)) == -1) {
1250 log_error("SO_REUSEADDR failed: %s", fc_strerror(fc_get_errno()));
1253 fc_nonblock(socklan);
1255 group = get_multicast_group(srvarg.announce == ANNOUNCE_IPV6);
1257 memset(&addr, 0, sizeof(addr));
1259 addr.saddr.sa_family = lan_family;
1261 #ifdef FREECIV_IPV6_SUPPORT
1262 if (addr.saddr.sa_family == AF_INET6) {
1263 addr.saddr_in6.sin6_family = AF_INET6;
1264 addr.saddr_in6.sin6_port = htons(SERVER_LAN_PORT);
1265 addr.saddr_in6.sin6_addr = in6addr_any;
1266 } else
1267 #endif /* IPv6 support */
1268 if (addr.saddr.sa_family == AF_INET) {
1269 addr.saddr_in4.sin_family = AF_INET;
1270 addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT);
1271 addr.saddr_in4.sin_addr.s_addr = htonl(INADDR_ANY);
1272 } else {
1273 fc_assert(FALSE);
1275 log_error("Unsupported address family in server_open_socket()");
1278 if (bind(socklan, &addr.saddr, sockaddr_size(&addr)) < 0) {
1279 log_error("Announcement socket binding failed: %s", fc_strerror(fc_get_errno()));
1282 #ifdef FREECIV_IPV6_SUPPORT
1283 if (addr.saddr.sa_family == AF_INET6) {
1284 inet_pton(AF_INET6, group, &mreq6.ipv6mr_multiaddr.s6_addr);
1285 mreq6.ipv6mr_interface = 0; /* TODO: Interface selection */
1286 if (setsockopt(socklan, IPPROTO_IPV6, FC_IPV6_ADD_MEMBERSHIP,
1287 (const char*)&mreq6, sizeof(mreq6)) < 0) {
1288 log_error("FC_IPV6_ADD_MEMBERSHIP (%s) failed: %s",
1289 group, fc_strerror(fc_get_errno()));
1291 } else
1292 #endif /* IPV6 Support */
1293 if (addr.saddr.sa_family == AF_INET) {
1294 fc_inet_aton(group, &mreq4.imr_multiaddr, FALSE);
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;
1316 /********************************************************************
1317 Initialize connection related stuff. Attention: Logging is not
1318 available within this functions!
1319 ********************************************************************/
1320 void init_connections(void)
1322 int i;
1324 game.all_connections = conn_list_new();
1325 game.est_connections = conn_list_new();
1326 game.glob_observers = conn_list_new();
1328 for (i = 0; i < MAX_NUM_CONNECTIONS; i++) {
1329 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;
1339 $DESCRIPTOR (tt_desc, "SYS$INPUT");
1340 status = sys$assign(&tt_desc, &tt_chan, 0, 0);
1341 if (!$VMS_STATUS_SUCCESS(status)) {
1342 lib$stop(status);
1345 #endif /* VMS */
1348 /**************************************************************************
1349 Starts processing of request packet from client.
1350 **************************************************************************/
1351 static void start_processing_request(struct connection *pconn,
1352 int request_id)
1354 fc_assert_ret(request_id);
1355 fc_assert_ret(pconn->server.currently_processed_request_id == 0);
1356 log_debug("start processing packet %d from connection %d",
1357 request_id, pconn->id);
1358 conn_compression_freeze(pconn);
1359 send_packet_processing_started(pconn);
1360 pconn->server.currently_processed_request_id = request_id;
1363 /**************************************************************************
1364 Finish processing of request packet from client.
1365 **************************************************************************/
1366 static void finish_processing_request(struct connection *pconn)
1368 if (!pconn || !pconn->used) {
1369 return;
1371 fc_assert_ret(pconn->server.currently_processed_request_id);
1372 log_debug("finish processing packet %d from connection %d",
1373 pconn->server.currently_processed_request_id, pconn->id);
1374 send_packet_processing_finished(pconn);
1375 pconn->server.currently_processed_request_id = 0;
1376 conn_compression_thaw(pconn);
1379 /****************************************************************************
1380 Ping a connection.
1381 ****************************************************************************/
1382 static void connection_ping(struct connection *pconn)
1384 struct timer *timer = timer_new(TIMER_USER, TIMER_ACTIVE);
1386 log_debug("sending ping to %s (open=%d)", conn_description(pconn),
1387 timer_list_size(pconn->server.ping_timers));
1388 timer_start(timer);
1389 timer_list_append(pconn->server.ping_timers, timer);
1390 send_packet_conn_ping(pconn);
1393 /**************************************************************************
1394 Handle response to ping.
1395 **************************************************************************/
1396 void handle_conn_pong(struct connection *pconn)
1398 struct timer *timer;
1400 if (timer_list_size(pconn->server.ping_timers) == 0) {
1401 log_error("got unexpected pong from %s", conn_description(pconn));
1402 return;
1405 timer = timer_list_front(pconn->server.ping_timers);
1406 pconn->ping_time = timer_read_seconds(timer);
1407 timer_list_pop_front(pconn->server.ping_timers);
1408 log_debug("got pong from %s (open=%d); ping time = %fs",
1409 conn_description(pconn),
1410 timer_list_size(pconn->server.ping_timers), pconn->ping_time);
1413 /**************************************************************************
1414 Handle client's regular hearbeat
1415 **************************************************************************/
1416 void handle_client_heartbeat(struct connection *pconn)
1418 log_debug("Received heartbeat");
1421 /**************************************************************************
1422 Send ping time info about all connections to all connections.
1423 **************************************************************************/
1424 static void send_ping_times_to_all(void)
1426 struct packet_conn_ping_info packet;
1427 int i;
1429 i = 0;
1430 conn_list_iterate(game.est_connections, pconn) {
1431 if (!pconn->used) {
1432 continue;
1434 fc_assert(i < ARRAY_SIZE(packet.conn_id));
1435 packet.conn_id[i] = pconn->id;
1436 packet.ping_time[i] = pconn->ping_time;
1437 i++;
1438 } conn_list_iterate_end;
1439 packet.connections = i;
1441 lsend_packet_conn_ping_info(game.est_connections, &packet);
1444 /********************************************************************
1445 Listen for UDP packets multicasted from clients requesting
1446 announcement of servers on the LAN.
1447 ********************************************************************/
1448 static void get_lanserver_announcement(void)
1450 fd_set readfs, exceptfs;
1451 fc_timeval tv;
1452 char msgbuf[128];
1453 struct data_in din;
1454 int type;
1456 if (srvarg.announce == ANNOUNCE_NONE) {
1457 return;
1460 FD_ZERO(&readfs);
1461 FD_ZERO(&exceptfs);
1462 FD_SET(socklan, &exceptfs);
1463 FD_SET(socklan, &readfs);
1465 tv.tv_sec = 0;
1466 tv.tv_usec = 0;
1468 while (fc_select(socklan + 1, &readfs, NULL, &exceptfs, &tv) == -1) {
1469 if (errno != EINTR) {
1470 log_error("select failed: %s", fc_strerror(fc_get_errno()));
1471 return;
1473 /* EINTR can happen sometimes, especially when compiling with -pg.
1474 * Generally we just want to run select again. */
1477 /* We would need a raw network connection for broadcast messages */
1478 if (FD_ISSET(socklan, &readfs)) {
1479 if (0 < recvfrom(socklan, msgbuf, sizeof(msgbuf), 0, NULL, NULL)) {
1480 dio_input_init(&din, msgbuf, 1);
1481 dio_get_uint8_raw(&din, &type);
1482 if (type == SERVER_LAN_VERSION) {
1483 log_debug("Received request for server LAN announcement.");
1484 send_lanserver_response();
1485 } else {
1486 log_debug("Received invalid request for server LAN announcement.");
1492 /********************************************************************
1493 This function broadcasts an UDP packet to clients with
1494 that requests information about the server state.
1495 ********************************************************************/
1496 /* We would need a raw network connection for broadcast messages */
1497 static void send_lanserver_response(void)
1499 #ifndef FREECIV_HAVE_WINSOCK
1500 unsigned char buffer[MAX_LEN_PACKET];
1501 #else /* FREECIV_HAVE_WINSOCK */
1502 char buffer[MAX_LEN_PACKET];
1503 #endif /* FREECIV_HAVE_WINSOCK */
1504 char hostname[512];
1505 char port[256];
1506 char version[256];
1507 char players[256];
1508 int nhumans;
1509 char humans[256];
1510 char status[256];
1511 struct raw_data_out dout;
1512 union fc_sockaddr addr;
1513 int socksend, setting = 1;
1514 const char *group;
1515 size_t size;
1516 #ifndef FREECIV_HAVE_WINSOCK
1517 unsigned char ttl;
1518 #endif
1520 /* Create a socket to broadcast to client. */
1521 if ((socksend = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1522 log_error("Lan response socket failed: %s", fc_strerror(fc_get_errno()));
1523 return;
1526 /* Set the UDP Multicast group IP address of the packet. */
1527 group = get_multicast_group(srvarg.announce == ANNOUNCE_IPV6);
1528 memset(&addr, 0, sizeof(addr));
1529 addr.saddr_in4.sin_family = AF_INET;
1530 addr.saddr_in4.sin_addr.s_addr = inet_addr(group);
1531 addr.saddr_in4.sin_port = htons(SERVER_LAN_PORT + 1);
1533 /* this setsockopt call fails on Windows 98, so we stick with the default
1534 * value of 1 on Windows, which should be fine in most cases */
1535 #ifndef FREECIV_HAVE_WINSOCK
1536 /* Set the Time-to-Live field for the packet. */
1537 ttl = SERVER_LAN_TTL;
1538 if (setsockopt(socksend, IPPROTO_IP, IP_MULTICAST_TTL,
1539 (const char*)&ttl, sizeof(ttl))) {
1540 log_error("setsockopt failed: %s", fc_strerror(fc_get_errno()));
1541 return;
1543 #endif /* FREECIV_HAVE_WINSOCK */
1545 if (setsockopt(socksend, SOL_SOCKET, SO_BROADCAST,
1546 (const char*)&setting, sizeof(setting))) {
1547 log_error("Lan response setsockopt failed: %s", fc_strerror(fc_get_errno()));
1548 return;
1551 /* Create a description of server state to send to clients. */
1552 if (srvarg.identity_name[0] != '\0') {
1553 sz_strlcpy(hostname, srvarg.identity_name);
1554 } else if (fc_gethostname(hostname, sizeof(hostname)) != 0) {
1555 sz_strlcpy(hostname, "none");
1558 fc_snprintf(version, sizeof(version), "%d.%d.%d%s",
1559 MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, VERSION_LABEL);
1561 switch (server_state()) {
1562 case S_S_INITIAL:
1563 /* TRANS: Game state for local server */
1564 fc_snprintf(status, sizeof(status), _("Pregame"));
1565 break;
1566 case S_S_RUNNING:
1567 /* TRANS: Game state for local server */
1568 fc_snprintf(status, sizeof(status), _("Running"));
1569 break;
1570 case S_S_OVER:
1571 /* TRANS: Game state for local server */
1572 fc_snprintf(status, sizeof(status), _("Game over"));
1573 break;
1576 fc_snprintf(players, sizeof(players), "%d",
1577 normal_player_count());
1579 nhumans = 0;
1580 players_iterate(pplayer) {
1581 if (pplayer->is_alive && is_human(pplayer)) {
1582 nhumans++;
1584 } players_iterate_end;
1585 fc_snprintf(humans, sizeof(humans), "%d", nhumans);
1587 fc_snprintf(port, sizeof(port), "%d",
1588 srvarg.port);
1590 dio_output_init(&dout, buffer, sizeof(buffer));
1591 dio_put_uint8_raw(&dout, SERVER_LAN_VERSION);
1592 dio_put_string_raw(&dout, hostname);
1593 dio_put_string_raw(&dout, port);
1594 dio_put_string_raw(&dout, version);
1595 dio_put_string_raw(&dout, status);
1596 dio_put_string_raw(&dout, players);
1597 dio_put_string_raw(&dout, humans);
1598 dio_put_string_raw(&dout, get_meta_message_string());
1599 size = dio_output_used(&dout);
1601 /* Sending packet to client with the information gathered above. */
1602 if (sendto(socksend, buffer, size, 0, &addr.saddr,
1603 sockaddr_size(&addr)) < 0) {
1604 log_error("landserver response sendto failed: %s",
1605 fc_strerror(fc_get_errno()));
1606 return;
1609 fc_closesocket(socksend);