26#ifdef FREECIV_HAVE_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
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>
97TEndpointInfo serv_info;
107# define lib$stop LIB$STOP
108# define sys$qiow SYS$QIOW
109# define sys$assign SYS$ASSIGN
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
139#if defined(FREECIV_HAVE_LIBREADLINE) || \
140 (!defined(FREECIV_SOCKET_ZERO_NOT_STDIN) && !defined(FREECIV_HAVE_LIBREADLINE))
149#ifndef FREECIV_SOCKET_ZERO_NOT_STDIN
150 log_normal(
_(
"Server cannot read standard input. Ignoring input."));
159#ifdef FREECIV_HAVE_LIBREADLINE
162#define HISTORY_FILENAME "freeciv-server_history"
163#define HISTORY_LENGTH 100
165static char *history_file = NULL;
166static bool readline_handled_input =
FALSE;
167static bool readline_initialized =
FALSE;
172static void handle_readline_input_callback(
char *line)
183 if (line[0] !=
'\0') {
193 readline_handled_input =
TRUE;
211#ifdef FREECIV_HAVE_LIBREADLINE
212 if (readline_initialized) {
213 rl_callback_handler_remove();
214 readline_initialized =
FALSE;
286#ifdef FREECIV_HAVE_LIBREADLINE
288 write_history(history_file);
289 history_truncate_file(history_file, HISTORY_LENGTH);
319 closing[num++] = pconn;
331 for (i = 0; i < num; i++) {
369 log_verbose(
"connection (%s) cut due to lagging player",
383 fd_set writefs, exceptfs;
398 tv.tv_sec = signsecs;
410 FD_SET(pconn->
sock, &writefs);
411 FD_SET(pconn->
sock, &exceptfs);
412 max_desc =
MAX(pconn->
sock, max_desc);
416 if (max_desc == -1) {
420 if (
fc_select(max_desc + 1, NULL, &writefs, &exceptfs, &tv) <= 0) {
428 if (FD_ISSET(pconn->
sock, &exceptfs)) {
429 log_verbose(
"connection (%s) cut due to exception data",
434 if (FD_ISSET(pconn->
sock, &writefs)) {
459 return NULL != ppacket->
data;
470#if PROCESSING_TIME_STATISTICS
471 struct timer *request_time = NULL;
477#if PROCESSING_TIME_STATISTICS
487#if PROCESSING_TIME_STATISTICS
500#if PROCESSING_TIME_STATISTICS
501 log_verbose(
"processed request %d in %gms", request_id,
510#if PROCESSING_TIME_STATISTICS
529 fd_set readfs, writefs, exceptfs;
531#ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
537#ifdef FREECIV_HAVE_LIBREADLINE
539 if (!
no_input && !readline_initialized) {
542 if (storage_dir != NULL) {
543 int fcdl = strlen(storage_dir) + 1;
546 if (fc_dir != NULL) {
551 =
fc_malloc(strlen(fc_dir) + 1 + strlen(HISTORY_FILENAME) + 1);
553 strcpy(history_file, fc_dir);
554 strcat(history_file,
"/");
555 strcat(history_file, HISTORY_FILENAME);
557 read_history(history_file);
565 rl_callback_handler_install((
char *)
"> ",
566 handle_readline_input_callback);
567 rl_attempted_completion_function = freeciv_completion;
569 readline_initialized =
TRUE;
591 static time_t last_noplayers;
598 if (last_noplayers != 0) {
603 log_normal(
_(
"Shutting down for lack of players."));
623 last_noplayers = time(NULL);
626 log_normal(
_(
"Shutting down in %d seconds for lack of players."),
631 log_normal(
_(
"Restarting in %d seconds for lack of players."),
649 if ((!pconn->server.is_closing
650 && 0 < timer_list_size(pconn->server.ping_timers)
652 (pconn->server.ping_timers))
656 if (pconn->access_level == ALLOW_HACK) {
657 log_verbose(
"connection (%s) [hack-level] ping timeout ignored",
660 log_verbose(
"connection (%s) cut due to ping timeout",
664 }
else if (pconn->established) {
677 && !pconn->server.is_closing
699#ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
719 FD_SET(pconn->
sock, &readfs);
721 FD_SET(pconn->
sock, &writefs);
723 FD_SET(pconn->
sock, &exceptfs);
724 max_desc =
MAX(pconn->
sock, max_desc);
729 selret =
fc_select(max_desc + 1, &readfs, &writefs, &exceptfs, &tv);
763 unsigned long status;
765 status = sys$qiow(EFN$C_ENF, tt_chan,
766 IO$_SENSEMODE | IO$M_TYPEAHDCNT, 0, 0, 0,
767 &ttchar,
sizeof(ttchar), 0, 0, 0, 0);
768 if (!$VMS_STATUS_SUCCESS(status)) {
771 if (ttchar.numchars) {
778#ifndef FREECIV_SOCKET_ZERO_NOT_STDIN
784 }
else if (selret < 0) {
800 if (FD_ISSET(s, &readfs)) {
817 && FD_ISSET(pconn->
sock, &exceptfs)) {
818 log_verbose(
"connection (%s) cut due to exception data",
823#ifdef FREECIV_SOCKET_ZERO_NOT_STDIN
824 if (!
no_input && (bufptr = fc_read_console())) {
832 if (!
no_input && FD_ISSET(0, &readfs)) {
833#ifdef FREECIV_HAVE_LIBREADLINE
834 rl_callback_read_char();
835 if (readline_handled_input) {
836 readline_handled_input =
FALSE;
851 log_debug(
"Got line: \"%s\" (" SIZE_T_PRINTF
", " SIZE_T_PRINTF
")",
buffer,
887 || !FD_ISSET(pconn->
sock, &readfs)) {
895 }
else if (-2 == nb) {
910 if (FD_ISSET(pconn->
sock, &writefs)) {
957 static unsigned short i = 0;
961 if (i == (
unsigned short) - 1) {
990 bool nameinfo =
FALSE;
991#ifdef FREECIV_IPV6_SUPPORT
992 char host[NI_MAXHOST], service[NI_MAXSERV];
993 char dst[INET6_ADDRSTRLEN];
995 struct hostent *from;
996 const char *host = NULL;
1000 fromlen =
sizeof(fromend);
1002 if ((new_sock = accept(sockfd, &fromend.
saddr, &fromlen)) == -1) {
1007#ifdef FREECIV_IPV6_SUPPORT
1008 if (fromend.
saddr.sa_family == AF_INET6) {
1009 inet_ntop(AF_INET6, &fromend.saddr_in6.sin6_addr,
1011 }
else if (fromend.
saddr.sa_family == AF_INET) {
1012 inet_ntop(AF_INET, &fromend.
saddr_in4.sin_addr, dst,
sizeof(dst));
1016 log_error(
"Unsupported address family in server_accept_connection()");
1021 dst = inet_ntoa(fromend.
saddr_in4.sin_addr);
1028 if (0 != strcmp(dst, pconn->server.ipaddr)) {
1032 log_verbose(
"Rejecting new connection from %s: maximum number of "
1033 "connections for this address exceeded (%d).",
1044#ifdef FREECIV_IPV6_SUPPORT
1045 nameinfo = (0 == getnameinfo(&fromend.
saddr, fromlen, host, NI_MAXHOST,
1046 service, NI_MAXSERV, NI_NUMERICSERV)
1047 &&
'\0' != host[0]);
1049 from = gethostbyaddr((
char *) &fromend.
saddr_in4.sin_addr,
1050 sizeof(fromend.
saddr_in4.sin_addr), AF_INET);
1051 if (NULL != from &&
'\0' != from->h_name[0]) {
1052 host = from->h_name;
1058 (nameinfo ? host : dst), dst);
1068 const char *client_ip)
1080 pconn->
sock = new_sock;
1118 log_error(
"maximum number of connections reached");
1132 struct ip_mreqn mreq4;
1134 struct ip_mreq mreq4;
1136 const char *cause, *group;
1139 struct fc_sockaddr_list *
list;
1144#ifdef FREECIV_IPV6_SUPPORT
1145 struct ipv6_mreq mreq6;
1148 log_verbose(
"Server attempting to listen on %s:%d",
1159 log_fatal(
_(
"Server: bad address: <%s:%d>."),
1173 s = socket(paddr->saddr.sa_family, SOCK_STREAM, 0);
1179 problematic = paddr;
1183#ifndef FREECIV_HAVE_WINSOCK
1185 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
1186 (
char *)&on,
sizeof(on)) == -1) {
1187 log_error(
"setsockopt SO_REUSEADDR failed: %s",
1195#ifdef FREECIV_IPV6_SUPPORT
1196 if (paddr->saddr.sa_family == AF_INET6) {
1198 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
1199 (
char *)&on,
sizeof(on)) == -1) {
1200 log_error(
"setsockopt IPV6_V6ONLY failed: %s",
1211 problematic = paddr;
1213 if (eno == EADDRNOTAVAIL) {
1237 problematic = paddr;
1247 if (problematic != NULL) {
1252 if (paddr != problematic) {
1259 fc_sockaddr_list_destroy(
list);
1267#ifdef FREECIV_IPV6_SUPPORT
1269 lan_family = AF_INET6;
1273 lan_family = AF_INET;
1277 if ((
socklan = socket(lan_family, SOCK_DGRAM, 0)) < 0) {
1283 if (setsockopt(
socklan, SOL_SOCKET, SO_REUSEADDR,
1284 (
char *)&on,
sizeof(on)) == -1) {
1292 memset(&addr, 0,
sizeof(addr));
1294 addr.
saddr.sa_family = lan_family;
1296#ifdef FREECIV_IPV6_SUPPORT
1297 if (addr.
saddr.sa_family == AF_INET6) {
1298 addr.saddr_in6.sin6_family = AF_INET6;
1300 addr.saddr_in6.sin6_addr = in6addr_any;
1303 if (addr.
saddr.sa_family == AF_INET) {
1306 addr.
saddr_in4.sin_addr.s_addr = htonl(INADDR_ANY);
1310 log_error(
"Unsupported address family in server_open_socket()");
1317#ifdef FREECIV_IPV6_SUPPORT
1318 if (addr.
saddr.sa_family == AF_INET6) {
1319 inet_pton(AF_INET6, group, &mreq6.ipv6mr_multiaddr.s6_addr);
1320 mreq6.ipv6mr_interface = 0;
1322 (
const char*)&mreq6,
sizeof(mreq6)) < 0) {
1323 log_error(
"FC_IPV6_ADD_MEMBERSHIP (%s) failed: %s",
1328 if (addr.
saddr.sa_family == AF_INET) {
1331 mreq4.imr_address.s_addr = htonl(INADDR_ANY);
1332 mreq4.imr_ifindex = 0;
1334 mreq4.imr_interface.s_addr = htonl(INADDR_ANY);
1337 if (setsockopt(
socklan, IPPROTO_IP, IP_ADD_MEMBERSHIP,
1338 (
const char*)&mreq4,
sizeof(mreq4)) < 0) {
1339 log_error(
"IP_ADD_MEMBERSHIP (%s) failed: %s",
1345 log_error(
"Unsupported address family for broadcasting.");
1367 pconn->
self = conn_list_new();
1368 conn_list_prepend(pconn->
self, pconn);
1374 $DESCRIPTOR (tt_desc,
"SYS$INPUT");
1375 status = sys$assign(&tt_desc, &tt_chan, 0, 0);
1376 if (!$VMS_STATUS_SUCCESS(
status)) {
1391 log_debug(
"start processing packet %d from connection %d",
1392 request_id, pconn->
id);
1403 if (!pconn || !pconn->
used) {
1407 log_debug(
"finish processing packet %d from connection %d",
1443 log_debug(
"got pong from %s (open=%d); ping time = %fs",
1470 packet.
conn_id[i] = pconn->id;
1485 fd_set readfs, exceptfs;
1504 if (errno != EINTR) {
1513 if (FD_ISSET(
socklan, &readfs)) {
1514 if (0 < recvfrom(
socklan, msgbuf,
sizeof(msgbuf), 0, NULL, NULL)) {
1518 log_debug(
"Received request for server LAN announcement.");
1521 log_debug(
"Received invalid request for server LAN announcement.");
1534#ifndef FREECIV_HAVE_WINSOCK
1551#ifndef FREECIV_HAVE_WINSOCK
1557 if ((socksend = socket(addr_fam, SOCK_DGRAM, 0)) < 0) {
1564 memset(&addr, 0,
sizeof(addr));
1565#ifdef FREECIV_IPV6_SUPPORT
1566 if (addr_fam == AF_INET6) {
1567 addr.saddr_in6.sin6_family = AF_INET6;
1569 inet_pton(addr_fam, group, &addr.saddr_in6.sin6_addr);
1574 addr.
saddr_in4.sin_addr.s_addr = inet_addr(group);
1580#ifndef FREECIV_HAVE_WINSOCK
1584#ifdef FREECIV_IPV6_SUPPORT
1585 if (addr_fam == AF_INET6) {
1586 proto = IPPROTO_IPV6;
1595 if (setsockopt(socksend, proto, IP_MULTICAST_TTL,
1596 (
const char*)&ttl,
sizeof(ttl))) {
1603 if (setsockopt(socksend, SOL_SOCKET, SO_BROADCAST,
1616 fc_snprintf(version,
sizeof(version),
"%d.%d.%d%s",
1617 MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION, VERSION_LABEL);
1639 if (pplayer->is_alive &&
is_human(pplayer)) {
1643 fc_snprintf(humans,
sizeof(humans),
"%d", nhumans);
1660 if (sendto(socksend, buffer,
size, 0, &addr.
saddr,
1662 log_error(
"landserver response sendto failed: %s",
void call_ai_refresh(void)
void auth_process_status(struct connection *pconn)
static struct ai_type * self
static struct fc_sockaddr_list * list
void lost_connection_to_client(struct connection *pconn)
void connection_close_server(struct connection *pconn, const char *reason)
struct player * conn_get_player(const struct connection *pconn)
struct connection * conn_by_user(const char *user_name)
void connections_set_close_callback(conn_close_fn_t func)
void flush_connection_send_buffer_all(struct connection *pc)
int get_next_request_id(int old_request_id)
void connection_do_buffer(struct connection *pc)
void conn_pattern_destroy(struct conn_pattern *ppattern)
void connection_common_init(struct connection *pconn)
const char * conn_description(const struct connection *pconn)
void connection_common_close(struct connection *pconn)
void conn_compression_freeze(struct connection *pconn)
struct connection * conn_by_number(int id)
int read_socket_data(int sock, struct socket_packet_buffer *buffer)
void connection_do_unbuffer(struct connection *pc)
bool conn_compression_thaw(struct connection *pconn)
#define conn_list_iterate(connlist, pconn)
#define conn_list_iterate_end
void con_prompt_enter_clear(void)
void con_prompt_init(void)
void con_prompt_enter(void)
void con_prompt_off(void)
void dio_output_init(struct raw_data_out *dout, void *destination, size_t dest_size)
void dio_put_uint8_raw(struct raw_data_out *dout, int value)
bool dio_get_uint8_raw(struct data_in *din, int *dest)
void dio_put_string_raw(struct raw_data_out *dout, const char *value)
size_t dio_output_used(struct raw_data_out *dout)
void dio_input_init(struct data_in *din, const void *src, size_t src_size)
#define MAX_NUM_CONNECTIONS
char * local_to_internal_string_malloc(const char *text)
int current_turn_timeout(void)
#define fc_assert_ret(condition)
#define log_verbose(message,...)
#define fc_assert(condition)
#define log_fatal(message,...)
#define log_debug(message,...)
#define log_normal(message,...)
#define log_error(message,...)
#define fc_calloc(n, esz)
void fc_shutdown_network(void)
int addr_family_for_announce_type(enum announce_type announce)
bool fc_inet_aton(const char *cp, struct in_addr *inp, bool addr_none_ok)
struct fc_sockaddr_list * net_lookup_service(const char *name, int port, enum fc_addr_family family)
void fc_closesocket(int sock)
void sockaddr_debug(union fc_sockaddr *addr, enum log_level lvl)
int sockaddr_size(union fc_sockaddr *addr)
void fc_nonblock(int sockfd)
int fc_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, fc_timeval *timeout)
struct timeval fc_timeval
#define fc_sockaddr_list_iterate_end
#define fc_sockaddr_list_iterate(sockaddrlist, paddr)
#define FC_IPV6_ADD_MEMBERSHIP
void packets_deinit(void)
#define get_packet_from_connection(pc, ptype)
int send_packet_conn_ping(struct connection *pc)
int send_packet_processing_finished(struct connection *pc)
int send_packet_processing_started(struct connection *pc)
void lsend_packet_conn_ping_info(struct conn_list *dest, const struct packet_conn_ping_info *packet)
void lsend_packet_server_shutdown(struct conn_list *dest)
struct player * player_by_name(const char *name)
struct player * player_by_user(const char *name)
#define players_iterate_end
#define players_iterate(_pplayer)
int normal_player_count(void)
void script_server_signal_emit(const char *signal_name,...)
static void cut_lagging_connection(struct connection *pconn)
static void connection_ping(struct connection *pconn)
static void server_conn_close_callback(struct connection *pconn)
static void send_lanserver_response(void)
static struct connection connections[MAX_NUM_CONNECTIONS]
int server_open_socket(void)
void init_connections(void)
static void really_close_connections(void)
int server_make_connection(int new_sock, const char *client_addr, const char *client_ip)
void handle_conn_pong(struct connection *pconn)
static int * listen_socks
static char * current_internal
static bool get_packet(struct connection *pconn, struct packet_to_handle *ppacket)
static void send_ping_times_to_all(void)
enum server_events server_sniff_all_input(void)
static void close_connection(struct connection *pconn)
void handle_client_heartbeat(struct connection *pconn)
void readline_atexit(void)
void close_connections_and_socket(void)
static void finish_processing_request(struct connection *pconn)
static void start_processing_request(struct connection *pconn, int request_id)
static void handle_stdin_close(void)
static const char * makeup_connection_name(int *id)
static int server_accept_connection(int sockfd)
static void get_lanserver_announcement(void)
static void incoming_client_packets(struct connection *pconn)
@ S_E_END_OF_TURN_TIMEOUT
#define SERVER_LAN_VERSION
bool make_dir(const char *pathname)
char * get_multicast_group(bool ipv6_preferred)
char * freeciv_storage_dir(void)
void save_game_auto(const char *save_reason, enum autosave_type type)
void set_server_state(enum server_states newstate)
struct server_arguments srvarg
bool server_packet_input(struct connection *pconn, void *packet, int type)
enum server_states server_state(void)
enum cmdlevel access_level_for_next_connection(void)
bool handle_stdin_input_free(struct connection *caller, char *str)
struct civ_game::@30::@34 server
struct conn_list * glob_observers
struct conn_list * est_connections
struct packet_game_info info
struct timer * save_timer
int additional_phase_seconds
int maxconnectionsperhost
struct timer * phase_timer
struct conn_list * all_connections
struct packet_timeout_info tinfo
int currently_processed_request_id
enum cmdlevel access_level
struct timer_list * ping_timers
char username[MAX_LEN_NAME]
struct connection::@57::@63 server
struct timer * last_write
char ipaddr[MAX_LEN_ADDR]
void(* incoming_packet_notify)(struct connection *pc, int packet_type, int size)
void(* outgoing_packet_notify)(struct connection *pc, int packet_type, int size, int request_id)
struct socket_packet_buffer * send_buffer
char capability[MAX_LEN_CAPSTR]
void(* notify_of_writable_data)(struct connection *pc, bool data_available_and_socket_full)
struct socket_packet_buffer * buffer
struct conn_pattern_list * ignore_list
enum cmdlevel granted_access_level
float ping_time[MAX_NUM_CONNECTIONS]
int conn_id[MAX_NUM_CONNECTIONS]
float seconds_to_phasedone
enum announce_type announce
int fc_snprintf(char *str, size_t n, const char *format,...)
int fc_gethostname(char *buf, size_t len)
const char * fc_strerror(fc_errno err)
fc_errno fc_get_errno(void)
#define sz_strlcpy(dest, src)
struct timer * timer_new(enum timer_timetype type, enum timer_use use)
void timer_destroy(struct timer *t)
void timer_start(struct timer *t)
double timer_read_seconds(struct timer *t)
struct timer * timer_renew(struct timer *t, enum timer_timetype type, enum timer_use use)
struct sockaddr_in saddr_in4
void send_updated_vote_totals(struct conn_list *dest)