////////////////////////////////////////////////////////////////////////////////////// // akashi - a server for Attorney Online 2 // // Copyright (C) 2020 scatterflower // // // // This program is free software: you can redistribute it and/or modify // // it under the terms of the GNU Affero General Public License as // // published by the Free Software Foundation, either version 3 of the // // License, or (at your option) any later version. // // // // This program is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY; without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // GNU Affero General Public License for more details. // // // // You should have received a copy of the GNU Affero General Public License // // along with this program. If not, see . // ////////////////////////////////////////////////////////////////////////////////////// #ifndef SERVER_H #define SERVER_H #include #include #include #include #include #include #include #include #include #include #include "include/aopacket.h" class Advertiser; class AOClient; class AreaData; class ConfigManager; class DBManager; class Discord; class MusicManager; class ULogger; class WSProxy; /** * @brief The class that represents the actual server as it is. */ class Server : public QObject { Q_OBJECT public: /** * @brief Creates a Server instance. * * @param p_port The TCP port to listen for connections on. * @param p_ws_port The WebSocket port to listen for connections on. * @param parent Qt-based parent, passed along to inherited constructor from QObject. */ Server(int p_port, int p_ws_port, QObject *parent = nullptr); /** * @brief Destructor for the Server class. * * @details Marks every Client, the WSProxy, the underlying #server, and the database manager to be deleted later. */ ~Server(); /** * @brief Starts the server. * * @details Amongst other things, this function starts the listening on the given TCP port, sets up the server * according to the configuration file, and starts listening on the WebSocket port if it is not `-1`. * * Advertising is not done here -- see Advertiser::contactMasterServer() for that. */ void start(); /** * @brief Enum to specifc different targets to send altered packets to a specific usergroup. */ enum class TARGET_TYPE { AUTHENTICATED, MODCHAT, ADVERT }; Q_ENUM(TARGET_TYPE) /** * @brief Returns a list of all clients currently in the server. * * @return A list of all clients currently in the server. */ QVector getClients(); /** * @brief Gets a pointer to a client by IPID. * * @param ipid The IPID to look for. * * @return A pointer to the client if found, a nullpointer if not. * * @see Server::getClientsByIpid() to get all clients ran by the same user. */ AOClient *getClient(QString ipid); /** * @brief Gets a list of pointers to all clients with the given IPID. * * @param ipid The IPID to look for. * * @return A list of clients whose IPID match. List may be empty. */ QList getClientsByIpid(QString ipid); /** * @brief Gets a pointer to a client by user ID. * * @param id The user ID to look for. * * @return A pointer to the client if found, a nullpointer if not. */ AOClient *getClientByID(int id); /** * @brief Returns the overall player count in the server. * * @return The overall player count in the server. */ int getPlayerCount(); /** * @brief Returns a list of the available characters on the server to use. * * @return A list of the available characters on the server to use. */ QStringList getCharacters(); /** * @brief Returns the count of available characters on the server to use. * * @return The count of available characters on the server to use. */ int getCharacterCount(); /** * @brief Get the available character by index. * * @param f_chr_id The index of the character. * * @return The character if it exist, otherwise an empty stirng. */ QString getCharacterById(int f_chr_id); /** * @brief Updates which characters are taken in the given area, and sends out an update packet to * all clients present the area. * * @param area The area in which to update the list of characters. */ void updateCharsTaken(AreaData *area); /** * @brief Sends a packet to all clients in a given area. * * @param packet The packet to send to the clients. * * @param area_index The index of the area to look for clients in. * * @note Does nothing if an area by the given index does not exist. */ void broadcast(AOPacket packet, int area_index); /** * @brief Sends a packet to all clients in the server. * * @param packet The packet to send to the clients. */ void broadcast(AOPacket packet); /** * @brief Sends a packet to a specific usergroup.. * * @param The packet to send to the clients. * * @param ENUM to determine the targets of the altered packet. */ void broadcast(AOPacket packet, TARGET_TYPE target); /** * @brief Sends a packet to clients, sends an altered packet to a specific usergroup. * * @param The packet to send to the clients. * * @param The altered packet to send to the other clients. * * @param ENUM to determine the targets of the altered packet. */ void broadcast(AOPacket packet, AOPacket other_packet, enum TARGET_TYPE target); /** * @brief Sends a packet to a single client. * * @param The packet send to the client. * * @param The temporary userID of the client. */ void unicast(AOPacket f_packet, int f_client_id); /** * @brief Returns the character's character ID (= their index in the character list). * * @param char_name The 'internal' name for the character whose character ID to look up. This is equivalent to * the name of the directory of the character. * * @return The character ID if a character with that name exists in the character selection list, `-1` if not. */ int getCharID(QString char_name); /** * @brief Checks if an IP is in a subnet of the IPBanlist. **/ bool isIPBanned(QHostAddress f_remote_IP); /** * @brief Returns the list of areas in the server. * * @return A list of areas. */ QVector getAreas(); /** * @brief Returns the number of areas in the server. */ int getAreaCount(); /** * @brief Returns a pointer to the area associated with the index. * * @param f_area_id The index of the area. * * @return A pointer to the area or null. */ AreaData *getAreaById(int f_area_id); /** * @brief Getter for an area specific buffer from the logger. */ QQueue getAreaBuffer(const QString &f_areaName); /** * @brief The names of the areas on the server. * * @return A list of names. */ QStringList getAreaNames(); /** * @brief Returns the name of the area associated with the index. * * @param f_area_id The index of the area. * * @return The name of the area or empty. */ QString getAreaName(int f_area_id); /** * @brief Returns the available songs on the server. * * @return A list of songs. */ QStringList getMusicList(); /** * @brief Returns the available backgrounds on the server. * * @return A list of backgrounds. */ QStringList getBackgrounds(); /** * @brief Returns a pointer to a database manager. * * @return A pointer to database manager. */ DBManager *getDatabaseManager(); /** * @brief The server-wide global timer. */ QTimer *timer; QStringList getCursedCharsTaken(AOClient *client, QStringList chars_taken); /** * @brief Returns whatever a game message may be broadcasted or not. * * @return True if expired; false otherwise. */ bool isMessageAllowed(); /** * @brief Starts a global timer that determines whatever a game message may be broadcasted or not. * * @param f_duration The duration of the message floodguard timer. */ void startMessageFloodguard(int f_duration); /** * @brief Attempts to parse a IPv6 mapped IPv4 to an IPv4. */ QHostAddress parseToIPv4(QHostAddress f_remote_ip); public slots: /** * @brief Convenience class to call a reload of available configuraiton elements. */ void reloadSettings(); /** * @brief Handles a new connection. * * @details The function creates an AOClient to represent the user, assigns a user ID to them, and * checks if the client is banned. */ void clientConnected(); /** * @brief Method to construct and reconstruct Discord Webhook Integration. * * @details Constructs or rebuilds Discord Object during server startup and configuration reload. */ void handleDiscordIntegration(); /** * @brief Marks a userID as free and ads it back to the available client id queue. */ void markIDFree(const int &f_user_id); signals: /** * @brief Sends the server name and description, emitted by /reload. * * @param p_name The server name. * @param p_desc The server description. */ void reloadRequest(QString p_name, QString p_desc); /** * @brief This signal is emitted whenever the current player count has changed. * * @param f_current_player The player count at the time the signal was emitted. */ void playerCountUpdated(int f_current_players); /** * @brief Triggers a partial update of the modern advertiser as some information, such as ports * can't be updated while the server is running. */ void updateHTTPConfiguration(); /** * @brief Sends a modcall webhook request, emitted by AOClient::pktModcall. * * @param f_name The character or OOC name of the client who sent the modcall. * @param f_area The name of the area the modcall was sent from. * @param f_reason The reason the client specified for the modcall. * @param f_buffer The area's log buffer. */ void modcallWebhookRequest(const QString &f_name, const QString &f_area, const QString &f_reason, const QQueue &f_buffer); /** * @brief Sends a ban webhook request, emitted by AOClient::cmdBan * @param f_ipid The IPID of the banned client. * @param f_moderator The moderator who issued the ban. * @param f_duration The duration of the ban in a human readable format. * @param f_reason The reason for the ban. * @param f_banID The ID of the issued ban. */ void banWebhookRequest(const QString &f_ipid, const QString &f_moderator, const QString &f_duration, const QString &f_reason, const int &f_banID); /** * @brief Signal connected to universal logger. Logs a client connection attempt. * @param f_ip_address The IP Address of the incoming connection. * @param f_ipid The IPID of the incoming connection. * @param f_hdid The HDID of the incoming connection. */ void logConnectionAttempt(const QString &f_ip_address, const QString &f_ipid, const QString &f_hwid); private: /** * @brief The proxy used for WebSocket connections. * * @see WSProxy and WSClient for an explanation as to why this is a thing. */ WSProxy *proxy; /** * @brief Listens for incoming TCP connections. */ QTcpServer *server; /** * @brief Handles Discord webhooks. */ Discord *discord; /** * @brief Handles HTTP server advertising. */ Advertiser *ms3_Advertiser; /** * @brief Advertises the server in a regular intervall. */ QTimer *AdvertiserTimer; /** * @brief Handles the universal log framework. */ ULogger *logger; /** * @brief Handles all musiclists. */ MusicManager *music_manager; /** * @brief The port through which the server will accept TCP connections. */ int port; /** * @brief The port through which the server will accept WebSocket connections. */ int ws_port; /** * @brief The collection of all currently connected clients. */ QVector m_clients; /** * @brief Collection of all clients with their userID as key. */ QHash m_clients_ids; /** * @brief Stack of all available IDs for clients. When this is empty the server * rejects any new connection attempt. */ QStack m_available_ids; /** * @brief The overall player count in the server. */ int m_player_count; /** * @brief The characters available on the server to use. */ QStringList m_characters; /** * @brief The areas on the server. */ QVector m_areas; /** * @brief The names of the areas on the server. * * @details Equivalent to iterating over #areas and getting the area names individually, but grouped together * here for faster access. */ QStringList m_area_names; /** * @brief The available songs on the server. * * @details Does **not** include the area names, the actual music list packet should be constructed from * #area_names and this combined. */ QStringList m_music_list; /** * @brief The backgrounds on the server that may be used in areas. */ QStringList m_backgrounds; /** * @brief Collection of all IPs that are banned. */ QStringList m_ipban_list; /** * @brief Timer until the next IC message can be sent. */ QTimer *m_message_floodguard_timer; /** * @brief If false, IC messages will be rejected. */ bool m_can_send_ic_messages = true; /** * @brief The database manager on the server, used to store users' bans and authorisation details. */ DBManager *db_manager; /** * @brief Connects new AOClient to logger and disconnect handling. **/ void hookupAOClient(AOClient *client); private slots: /** * @brief Increase the current player count by one. */ void increasePlayerCount(); /** * @brief Decrease the current player count based on the client id provided. * * @param f_client_id The client id of the client to check. */ void decreasePlayerCount(); /** * @brief Allow game messages to be broadcasted. */ void allowMessage(); }; #endif // SERVER_H