14 #include <fc_config.h>
19 #include <QCoreApplication>
21 #include <QLocalServer>
22 #include <QNetworkDatagram>
34 #include "fc_version.h"
61 #define PROCESSING_TIME_STATISTICS 0
79 if (pconn->
server.ping_timers !=
nullptr) {
80 while (!pconn->
server.ping_timers->isEmpty()) {
83 delete pconn->
server.ping_timers;
84 pconn->
server.ping_timers =
nullptr;
87 conn_pattern_list_destroy(pconn->
server.ignore_list);
88 pconn->
server.ignore_list =
nullptr;
151 if (pconn->
used && pconn->
server.is_closing) {
152 closing[num++] = pconn;
164 for (i = 0; i < num; i++) {
180 pconn->
server.is_closing =
true;
192 if (pconn->
used && !pconn->
server.is_closing) {
193 if (!pconn->
sock->isOpen()) {
194 qDebug(
"connection (%s) cut due to exception data",
210 enum packet_type
type;
221 return nullptr != ppacket->
data;
232 #if PROCESSING_TIME_STATISTICS
239 #if PROCESSING_TIME_STATISTICS
246 pconn->
server.last_request_id_seen =
249 #if PROCESSING_TIME_STATISTICS
250 request_id = pconn->
server.last_request_id_seen;
257 ::operator
delete(packet.
data);
262 #if PROCESSING_TIME_STATISTICS
263 qDebug(
"processed request %d in %gms", request_id,
272 #if PROCESSING_TIME_STATISTICS
287 static unsigned short i = 0;
291 if (i ==
static_cast<unsigned short>(-1)) {
311 const QString &ip_addr)
321 pconn->
sock = new_sock;
328 pconn->
server.currently_processed_request_id = 0;
329 pconn->
server.last_request_id_seen = 0;
330 pconn->
server.auth_tries = 0;
331 pconn->
server.auth_settime = 0;
333 pconn->
server.ping_timers =
new QList<civtimer *>;
335 pconn->
server.ignore_list =
337 pconn->
server.is_closing =
false;
343 pconn->
addr = client_addr;
348 qDebug(
"connection (%s) from %s (%s)", pconn->
username,
349 qUtf8Printable(pconn->
addr), pconn->
server.ipaddr);
355 pconn->
server.ping_timers->append(timer);
361 qCritical(
"maximum number of connections reached");
362 new_sock->deleteLater();
374 auto server = std::make_unique<QLocalServer>();
375 server->setSocketOptions(QLocalServer::UserAccessOption);
382 qCritical().noquote()
383 << QString(
_(
"Server: cannot listen on local socket %1: %2"))
385 .arg(
server->errorString());
391 auto server = std::make_unique<QTcpServer>();
395 qInfo(
"Server attempting to listen on %s:%d",
408 _(
"Server: cannot listen on port %1: %2"))
410 .arg(
server->errorString())));
421 enum QHostAddress::SpecialAddress address_type;
424 address_type = QHostAddress::AnyIPv6;
428 address_type = QHostAddress::AnyIPv4;
434 QAbstractSocket::ReuseAddressHint)) {
435 qCritical(
"SO_REUSEADDR failed: %s",
436 udp_socket->errorString().toLocal8Bit().data());
440 if (!
udp_socket->joinMulticastGroup(QHostAddress(group))) {
441 qCritical(
"Announcement socket binding failed: %s",
442 udp_socket->errorString().toLocal8Bit().data());
464 pconn->
self = conn_list_new();
465 conn_list_prepend(pconn->
self, pconn);
477 log_debug(
"start processing packet %d from connection %d", request_id,
480 send_packet_processing_started(pconn);
481 pconn->
server.currently_processed_request_id = request_id;
489 if (!pconn || !pconn->
used) {
493 log_debug(
"finish processing packet %d from connection %d",
494 pconn->
server.currently_processed_request_id, pconn->
id);
495 send_packet_processing_finished(pconn);
496 pconn->
server.currently_processed_request_id = 0;
505 time_t now = time(NULL);
509 while ((head = unit_wait_list_front(
server.unit_waits))
520 unit_wait_list_pop_front(
server.unit_waits);
532 pconn->
server.ping_timers->size());
534 pconn->
server.ping_timers->append(timer);
535 send_packet_conn_ping(pconn);
545 if (pconn->
server.ping_timers->size() == 0) {
550 timer = pconn->
server.ping_timers->front();
554 log_time(QStringLiteral(
"got pong from %1 (open=%2); ping time = %3s")
556 .arg(pconn->
server.ping_timers->size())
582 QNetworkDatagram qnd =
udp_socket->receiveDatagram();
583 auto data = qnd.data();
587 log_debug(
"Received request for server LAN announcement.");
590 log_debug(
"Received invalid request for server LAN announcement.");
613 enum QHostAddress::SpecialAddress address_type;
614 QUdpSocket lockal_udpsock;
620 address_type = QHostAddress::AnyIPv6;
624 address_type = QHostAddress::AnyIPv4;
627 QAbstractSocket::ReuseAddressHint);
629 lockal_udpsock.joinMulticastGroup(QHostAddress(group));
637 fc_snprintf(version,
sizeof(version),
"%d.%d.%d%s", MAJOR_VERSION,
638 MINOR_VERSION, PATCH_VERSION, VERSION_LABEL);
660 if (pplayer->is_alive &&
is_human(pplayer)) {
665 fc_snprintf(humans,
sizeof(humans),
"%d", nhumans);
679 lockal_udpsock.writeDatagram(QByteArray(buffer,
size), QHostAddress(group),
681 lockal_udpsock.close();
void lost_connection_to_client(struct connection *pconn)
High-level server stuff when connection to client is closed or lost.
void connection_close_server(struct connection *pconn, const QString &reason)
Close a connection.
void connections_set_close_callback(conn_close_fn_t func)
Register the close_callback.
void flush_connection_send_buffer_all(struct connection *pc)
Flush'em.
int get_next_request_id(int old_request_id)
Get next request id.
struct player * conn_get_player(const struct connection *pconn)
Returns the player that this connection is attached to, or nullptr.
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 connection_do_buffer(struct connection *pc)
Turn on buffering, using a counter so that calls may be nested.
void conn_pattern_destroy(struct conn_pattern *ppattern)
Free a connection pattern.
void connection_common_init(struct connection *pconn)
Initialize common part of connection structure.
void connection_common_close(struct connection *pconn)
Connection closing part common to server and client.
void conn_compression_freeze(struct connection *pconn)
Freeze the connection.
struct connection * conn_by_number(int id)
Find connection by id, from game.all_connections.
struct connection * conn_by_user(const char *user_name)
Find connection by exact user name, from game.all_connections, case-insensitve.
void connection_do_unbuffer(struct connection *pc)
Turn off buffering if internal counter of number of times buffering was turned on falls to zero,...
bool conn_compression_thaw(struct connection *pconn)
Thaw the connection.
void dio_output_init(struct raw_data_out *dout, void *destination, size_t dest_size)
Initializes the output to the given output buffer and the given buffer size.
void dio_put_uint8_raw(struct raw_data_out *dout, int value)
Insert value using 8 bits.
bool dio_get_uint8_raw(struct data_in *din, int *dest)
Receive uint8 value to dest.
void dio_put_string_raw(struct raw_data_out *dout, const char *value)
Insert nullptr-terminated string.
size_t dio_output_used(struct raw_data_out *dout)
Return the maximum number of bytes used.
void dio_input_init(struct data_in *din, const void *src, size_t src_size)
Initializes the input to the given input buffer and the given number of valid input bytes.
#define MAX_NUM_CONNECTIONS
struct unit * game_unit_by_number(int id)
Find unit out of all units in game: now uses fast idex method, instead of looking through all units o...
void log_time(const QString &msg, bool log)
#define fc_assert_ret(condition)
#define fc_assert_ret_msg(condition, message,...)
#define log_debug(message,...)
void packets_deinit()
Call when there is no longer a requirement for protocol processing.
#define get_packet_from_connection(pc, ptype)
struct player * player_by_name(const char *name)
Find player by given name.
struct player * player_by_user(const char *name)
Find player by its user name (not player/leader name)
#define players_iterate_end
#define players_iterate(_pplayer)
int normal_player_count()
Return the number of non-barbarian players.
void connection_ping(struct connection *pconn)
Ping a connection.
void init_connections()
Initialize connection related stuff.
static void server_conn_close_callback(struct connection *pconn)
Break a client connection.
static struct connection connections[MAX_NUM_CONNECTIONS]
static const char * makeup_connection_name(int *id)
Make up a name for the connection, before we get any data from it to use as a sensible name.
void handle_conn_pong(struct connection *pconn)
Handle response to ping.
static void send_lanserver_response()
This function broadcasts an UDP packet to clients with that requests information about the server sta...
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.
static bool get_packet(struct connection *pconn, struct packet_to_handle *ppacket)
Simplify a loop by wrapping get_packet_from_connection.
void close_connections_and_socket()
Close all network stuff: connections, listening sockets, metaserver connection...
static void close_connection(struct connection *pconn)
Close the connection (very low-level).
void really_close_connections()
Now really close connections marked as 'is_closing'.
static QUdpSocket * udp_socket
void handle_client_heartbeat(struct connection *pconn)
Handle client's regular hearbeat.
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...
static void finish_processing_request(struct connection *pconn)
Finish processing of request packet from client.
void flush_packets()
Attempt to flush all information in the send buffers for upto 'netwait' seconds.
static void start_processing_request(struct connection *pconn, int request_id)
Starts processing of request packet from client.
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.
#define SERVER_LAN_VERSION
char * get_multicast_group(bool ipv6_preferred)
Returns string which gives the multicast group IP address for finding servers on the LAN,...
struct server_arguments srvarg
enum server_states server_state()
Return current server state.
bool server_packet_input(struct connection *pconn, void *packet, int type)
Returns FALSE if connection should be closed (because the clients was rejected).
enum cmdlevel access_level_for_next_connection()
Return access level for next connection.
struct conn_list * glob_observers
struct conn_list * est_connections
struct conn_list * all_connections
enum cmdlevel access_level
struct connection::@55::@61 server
char username[MAX_LEN_NAME]
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)
enum announce_type announce
enum unit_activity activity
enum unit_activity activity
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
int fc_gethostname(char *buf, size_t len)
Call gethostname() if supported, else just returns -1.
#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.
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 send_updated_vote_totals(struct conn_list *dest)
Sends a packet_vote_update to every conn in dest.