24 #include <QCoreApplication>
28 #include <QLocalSocket>
34 #include <QMutexLocker>
37 #include <QtCore/QSocketNotifier>
43 #include <readline/history.h>
44 #include <readline/readline.h>
88 void handle_readline_input_callback(
char *line)
90 if (line ==
nullptr) {
94 if (line[0] !=
'\0') {
101 delete[] line_internal;
109 void fc_interface_init_server()
132 std::optional<socket_server> srv_prepare()
173 QString testfilename;
177 if (testfilename.isEmpty()) {
178 qFatal(
_(
"Ruleset directory \"%s\" not found"),
191 load_rulesets(
nullptr,
nullptr,
false,
nullptr,
true,
false,
true);
197 qInfo(
_(
"Sending info to metaserver <%s>."),
203 "metaserver connection."));
217 detail::async_readline_wrapper::async_readline_wrapper(
bool interactive,
219 : QThread(parent), m_interactive(interactive), m_stop{}
226 void detail::async_readline_wrapper::stop() { m_stop =
true; }
232 void detail::async_readline_wrapper::wait_for_input()
236 while (line.isEmpty()) {
242 char *buffer = readline(
"> ");
243 if (buffer ==
nullptr) {
247 if (buffer && buffer[0] !=
'\0') {
251 line = QString::fromLocal8Bit(buffer);
254 f.open(stdin, QIODevice::ReadOnly);
255 line = QString::fromLocal8Bit(f.readLine());
259 emit line_available(line);
263 QRecursiveMutex server::s_stdin_mutex = QRecursiveMutex();
272 QMutexLocker lock(&s_stdin_mutex);
289 auto wrapper =
new detail::async_readline_wrapper(
m_interactive);
290 wrapper->moveToThread(wrapper);
291 connect(wrapper, &detail::async_readline_wrapper::line_available,
this,
293 connect(
this, &server::input_requested, wrapper,
294 &detail::async_readline_wrapper::wait_for_input);
302 new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read,
this);
303 connect(notifier, &QSocketNotifier::activated,
this,
310 fc_interface_init_server();
311 auto server = srv_prepare();
318 if (std::holds_alternative<std::unique_ptr<QTcpServer>>(
m_server)) {
319 auto &tcp = std::get<std::unique_ptr<QTcpServer>>(
m_server);
320 connect(tcp.get(), &QTcpServer::newConnection,
this,
322 connect(tcp.get(), &QTcpServer::acceptError,
323 [](QAbstractSocket::SocketError error) {
324 qCritical(
"Error accepting connection: %d", error);
326 }
else if (std::holds_alternative<std::unique_ptr<QLocalServer>>(
328 auto &local = std::get<std::unique_ptr<QLocalServer>>(
m_server);
329 connect(local.get(), &QLocalServer::newConnection,
this,
354 emit input_requested();
364 QMutexLocker lock(&s_stdin_mutex);
385 auto history_file_encoded = history_file.toLocal8Bit();
386 write_history(history_file_encoded.constData());
387 history_truncate_file(history_file_encoded.constData(),
HISTORY_LENGTH);
391 rl_callback_handler_remove();
410 if (QDir().mkpath(storage_dir)) {
414 read_history(history_file.toLocal8Bit().constData());
420 rl_attempted_completion_function = synchronized_completion;
422 rl_callback_handler_install((
char *)
"> ", handle_readline_input_callback);
443 while (
server->hasPendingConnections()) {
444 auto *socket =
server->nextPendingConnection();
445 socket->setParent(
this);
448 QStringLiteral(
"local"))
452 connect(socket, &QLocalSocket::errorOccurred,
this,
465 socket->deleteLater();
477 QMutexLocker lock(&s_stdin_mutex);
484 while (
server->hasPendingConnections()) {
485 auto *socket =
server->nextPendingConnection();
486 socket->setParent(
this);
490 auto remote = socket->peerAddress().toString();
492 auto host_info = QHostInfo::fromName(remote);
493 if (host_info.error() == QHostInfo::NoError) {
494 remote = host_info.hostName();
499 qDebug(
"Rejecting new connection from %s: maximum number of "
500 "connections exceeded (%d).",
502 socket->deleteLater();
515 if (
const auto *other = qobject_cast<QTcpSocket *>(pconn->sock);
516 socket->peerAddress().isEqual(
517 other->peerAddress(), QHostAddress::TolerantConversion)) {
520 if (++count >=
game.
server.maxconnectionsperhost) {
521 qWarning(
"Rejecting new connection from %s: maximum number of "
522 "connections for this address exceeded (%d).",
523 qUtf8Printable(remote),
527 socket->deleteLater();
533 socket->deleteLater();
539 socket->peerAddress().toString())
543 connect(socket, &QAbstractSocket::errorOccurred,
this,
565 QMutexLocker lock(&s_stdin_mutex);
572 if ((!pconn->server.is_closing && 0 < pconn->server.ping_timers->size()
575 || pconn->ping_time >
game.
server.pingtimeout) {
577 if (pconn->access_level == ALLOW_HACK) {
578 qDebug(
"connection (%s) [hack-level] ping timeout ignored",
581 qDebug(
"connection (%s) cut due to ping timeout",
585 }
else if (pconn->established) {
603 QMutexLocker lock(&s_stdin_mutex);
607 auto *socket =
dynamic_cast<QTcpSocket *
>(sender());
608 if (socket ==
nullptr) {
615 if (pconn->sock == socket) {
632 QMutexLocker lock(&s_stdin_mutex);
636 auto *socket =
dynamic_cast<QIODevice *
>(sender());
637 if (socket ==
nullptr) {
644 if (pconn->sock == socket && !pconn->server.is_closing) {
649 }
else if (-2 == nb) {
671 QMutexLocker lock(&s_stdin_mutex);
673 auto buffer = line.toUtf8();
684 emit input_requested();
693 char **server::synchronized_completion(
const char *text,
int start,
int end)
695 QMutexLocker lock(&s_stdin_mutex);
708 rl_callback_read_char();
711 f.open(stdin, QIODevice::ReadOnly);
719 qInfo(
_(
"Reached end of standard input."));
720 }
else if (f.canReadLine()) {
723 auto line = f.readLine();
724 auto *non_const_line =
727 free(non_const_line);
742 QMutexLocker lock(&s_stdin_mutex);
762 qInfo(
_(
"Now accepting new client connections on port %d."),
srvarg.
port);
778 QMutexLocker lock(&s_stdin_mutex);
793 QMutexLocker lock(&s_stdin_mutex);
816 log_time(QStringLiteral(
"End/start-turn server/ai activities: %1 seconds")
836 if (pmapdef !=
nullptr) {
857 log_debug(
"Inresponsive between turns %g seconds",
870 QMutexLocker lock(&s_stdin_mutex);
913 QMutexLocker lock(&s_stdin_mutex);
967 QMutexLocker lock(&s_stdin_mutex);
1020 qInfo(
_(
"Shutting down in %d seconds for lack of players."),
1025 qInfo(
_(
"Restarting in %d seconds for lack of players."),
1046 QMutexLocker lock(&s_stdin_mutex);
1063 load_rulesets(
nullptr,
nullptr,
false,
nullptr,
true,
false,
true);
1075 QMutexLocker lock(&s_stdin_mutex);
1081 qDebug(
"Quitidle timer fired but someone is connected; not quitting");
1086 qInfo(
_(
"Shutting down for lack of players."));
1089 qInfo(
_(
"Restarting for lack of players."));
1112 QMutexLocker lock(&s_stdin_mutex);
#define ai_timer_init(...)
void call_ai_refresh()
Call ai refresh() callback for all players.
void auth_process_status(struct connection *pconn)
Checks on where in the authentication process we are.
~server() override
Shut down a server.
void accept_local_connections()
Server accepts connections over local socket: Low level socket stuff, and basic-initialize the connec...
void init_interactive()
Initializes interactive handling of stdin with libreadline.
void begin_phase()
Do everything needed to start a new phase on top of calling begin_phase.
bool prepare_game()
Prepares for a new game.
civtimer * m_between_turns_timer
void pulse()
Called every second.
void error_on_socket()
Called when there was an error on a socket.
void end_turn()
Do everything needed to end a turn on top of calling end_turn.
QObject * m_stdin_notifier
void input_on_socket()
Called when there's something to read on a socket.
bool shut_game_down()
Shuts a game down when all players have left.
bool m_need_send_pending_events
void input_on_stdin()
Called when there's something to read on stdin.
bool m_someone_ever_connected
void quit_idle()
Quit because we're idle (ie no one was connected in the last srvarg.quitidle seconds).
void update_game_state()
Checks if the game state has changed and take action if appropriate.
void end_phase()
Do everything needed to end a phase on top of calling end_phase.
void send_pings()
Sends pings to clients if needed.
void accept_tcp_connections()
Server accepts connections from client: Low level socket stuff, and basic-initialize the connection s...
void begin_turn()
Do everything needed to start a new turn on top of calling begin_turn.
bool is_ready() const
Checks if the server is ready for the event loop to start.
QTimer * m_quitidle_timer
void connection_close_server(struct connection *pconn, const QString &reason)
Close a connection.
void conn_list_do_unbuffer(struct conn_list *dest)
Convenience functions to unbuffer a list of connections.
int read_socket_data(QIODevice *sock, struct socket_packet_buffer *buffer)
Read data from socket, and check if a packet is ready.
const char * conn_description(const struct connection *pconn, bool is_private)
° Return pointer to static string containing a description for this ° connection, based on pconn->nam...
void conn_list_do_buffer(struct conn_list *dest)
Convenience functions to buffer a list of connections.
#define conn_list_iterate(connlist, pconn)
#define conn_list_iterate_end
void con_log_init(const QString &log_filename)
Initialize logging via console.
void con_prompt_off()
Do not print a prompt after log messages.
void con_flush()
Ensure timely update.
void con_prompt_init()
Initialize prompt; display initial message.
void con_write(enum rfc_status rfc_status, const char *message,...)
Write to console and add line-break, and show prompt if required.
void con_prompt_enter()
User pressed enter: will need a new prompt.
void diplhand_init()
Initialize diplhand module.
void edithand_init()
Initialize data structures required for edit mode.
struct functions * fc_interface_funcs()
Return the function pointer.
void fc_interface_init()
Test and initialize the functions.
#define MAX_NUM_CONNECTIONS
bool fcdb_init(const char *conf_file)
Initialize freeciv database system.
char * local_to_internal_string_malloc(const char *text)
int current_turn_timeout()
Return timeout value for the current turn.
void log_time(const QString &msg, bool log)
#define log_debug(message,...)
void destroy_extra(struct tile *ptile, struct extra_type *pextra)
Remove extra from tile.
void create_extra(struct tile *ptile, const extra_type *pextra, struct player *pplayer)
Create extra to tile.
bool map_is_known_and_seen(const struct tile *ptile, const struct player *pplayer, enum vision_layer vlayer)
Returns whether the layer 'vlayer' of the tile 'ptile' is known and seen by the player 'pplayer'.
void mapimg_reset()
Reset the map image subsystem.
int mapimg_count()
Return the number of map image definitions.
const char * mapimg_error()
Returns the last error.
struct mapdef * mapimg_isvalid(int id)
Check if a map image definition is valid.
void mapimg_init(mapimg_tile_known_func mapimg_tile_known, mapimg_tile_terrain_func mapimg_tile_terrain, mapimg_tile_player_func mapimg_tile_owner, mapimg_tile_player_func mapimg_tile_city, mapimg_tile_player_func mapimg_tile_unit, mapimg_plrcolor_count_func mapimg_plrcolor_count, mapimg_plrcolor_get_func mapimg_plrcolor_get)
Initialisation of the map image subsystem.
bool mapimg_create(struct mapdef *pmapdef, bool force, const char *savename, const char *path)
Create the requested map image.
void event_cache_clear()
Remove all events from the cache.
void send_pending_events(struct connection *pconn, bool include_public)
Send all available events.
void fc_rand_set_init(bool init)
Sets whether the current state has been initialized.
bool load_rulesets(const char *restore, const char *alt, bool compat_mode, rs_conversion_logger logger, bool act, bool buffer_script, bool load_luadata)
Loads the rulesets.
void save_system_close()
Close saving system.
void rank_users(bool interrupt)
At the end of a game, figure the winners and losers of the game and output to a suitable place.
void script_server_signal_emit(const char *signal_name,...)
Invoke all the callback functions attached to a given signal.
void connection_ping(struct connection *pconn)
Ping a connection.
void init_connections()
Initialize connection related stuff.
void get_lanserver_announcement()
Listen for UDP packets multicasted from clients requesting announcement of servers on the LAN.
void incoming_client_packets(struct connection *pconn)
Handle all incoming packets on a client connection.
void really_close_connections()
Now really close connections marked as 'is_closing'.
int server_make_connection(QIODevice *new_sock, const QString &client_addr, const QString &ip_addr)
Server accepts connection from client: Low level socket stuff, and basic-initialize the connection st...
std::optional< socket_server > server_open_socket()
Open server socket to be used to accept client connections and open a server socket for server LAN an...
void finish_unit_waits()
Process all unit waits that are expired.
static const int HISTORY_LENGTH
static const char * HISTORY_FILENAME
void settings_init(bool act)
Initialize stuff related to this code module.
const QStringList & get_data_dirs()
Returns a list of data directory paths, in the order in which they should be searched.
QString fileinfoname(const QStringList &dirs, const QString &filename)
Returns a filename to access the specified file from a directory by searching all specified directori...
QString freeciv_storage_dir()
Returns string which gives freeciv storage dir.
void server_game_init(bool keep_ruleset_value)
Initialize game data for the server (corresponds to server_game_free).
void srv_scores()
Score calculation.
void srv_ready()
Set up one game.
const char * aifill(int amount)
Fill or remove players to meet the given aifill.
void check_for_full_turn_done()
Check if turn is really done.
int mapimg_server_plrcolor_count()
Helper function for the mapimg module - number of player colors.
int server_plr_tile_city_id_get(const struct tile *ptile, const struct player *pplayer)
Returns the id of the city the player map of 'pplayer' has at 'ptile' or IDENTITY_NUMBER_ZERO if the ...
void server_game_free()
Free game data that we reinitialize as part of a server soft restart.
player * mapimg_server_tile_owner(const struct tile *ptile, const struct player *pplayer, bool knowledge)
Helper function for the mapimg module - tile owner.
void save_game_auto(const char *save_reason, enum autosave_type type)
Save game with autosave filename.
const char * server_ss_name_get(server_setting_id id)
Returns the name of the server setting with the specified id.
bool check_for_game_over()
Returns TRUE if any one game end condition is fulfilled, FALSE otherwise.
player * mapimg_server_tile_unit(const struct tile *ptile, const struct player *pplayer, bool knowledge)
Helper function for the mapimg module - unit owner.
void set_server_state(enum server_states newstate)
Set current server state.
void server_quit()
Quit the server and exit.
struct server_arguments srvarg
known_type mapimg_server_tile_known(const struct tile *ptile, const struct player *pplayer, bool knowledge)
Helper function for the mapimg module - tile knowledge.
bool game_was_started()
Returns iff the game was started once upon a time.
bool server_ss_val_bool_get(server_setting_id id)
Returns the value of the boolean server setting with the specified id.
server_setting_id server_ss_by_name(const char *name)
Returns the id of the server setting with the specified name.
enum server_states server_state()
Return current server state.
rgbcolor * mapimg_server_plrcolor_get(int i)
Helper function for the mapimg module - one player color.
void srv_init()
Initialize freeciv server.
int server_ss_val_int_get(server_setting_id id)
Returns the value of the integer server setting with the specified id.
unsigned int server_ss_val_bitwise_get(server_setting_id id)
Returns the value of the bitwise server setting with the specified id.
enum sset_type server_ss_type_get(server_setting_id id)
Returns the type of the server setting with the specified id.
terrain * mapimg_server_tile_terrain(const struct tile *ptile, const struct player *pplayer, bool knowledge)
Helper function for the mapimg module - tile terrain.
player * mapimg_server_tile_city(const struct tile *ptile, const struct player *pplayer, bool knowledge)
Helper function for the mapimg module - city owner.
char ** freeciv_completion(const char *text, int start, int end)
Attempt to complete on the contents of TEXT.
void stdinhand_init()
Initialize stuff related to this code module.
bool handle_stdin_input(struct connection *caller, char *str)
Main entry point for "command input".
bool read_init_script(struct connection *caller, const char *script_filename, bool from_cmdline, bool check)
Main entry point for reading an init script.
bool load_command(struct connection *caller, const char *filename, bool check, bool cmdline_load)
Loads a file, complete with access checks and error messages sent back to the caller on failure.
bool should_quit()
Returns whether the server should exit after a command.
struct civ_game::@28::@32 server
struct conn_list * est_connections
struct packet_game_info info
struct conn_list * all_connections
struct packet_timeout_info tinfo
int(* player_tile_city_id_get)(const struct tile *ptile, const struct player *pplayer)
int(* server_setting_val_int_get)(server_setting_id id)
void(* create_extra)(struct tile *ptile, const extra_type *pextra, struct player *pplayer)
bool(* player_tile_vision_get)(const struct tile *ptile, const struct player *pplayer, enum vision_layer vision)
const char *(* server_setting_name_get)(server_setting_id id)
bool(* server_setting_val_bool_get)(server_setting_id id)
void(* destroy_extra)(struct tile *ptile, struct extra_type *pextra)
server_setting_id(* server_setting_by_name)(const char *name)
unsigned int(* server_setting_val_bitwise_get)(server_setting_id id)
enum sset_type(* server_setting_type_get)(server_setting_id id)
bool metaconnection_persistent
#define sz_strlcpy(dest, src)
void timer_destroy(civtimer *t)
Deletes timer.
double timer_read_seconds(civtimer *t)
Read value from timer.
civtimer * timer_new(enum timer_timetype type, enum timer_use use)
Allocate a new timer with specified "type" and "use".
void timer_start(civtimer *t)
Start timing, adding to previous accumulated time if timer has not been cleared.
void timer_clear(civtimer *t)
Reset accumulated time to zero, and stop timer if going.
civtimer * timer_renew(civtimer *t, enum timer_timetype type, enum timer_use use)
Allocate a new timer, or reuse t, with specified "type" and "use".
void voting_init()
Initialize data structures used by this module.