#pragma once #include #include #include #include #include #include #include "Account.hh" #include "Channel.hh" #include "IPV4RangeSet.hh" #include "PatchFileIndex.hh" #include "Version.hh" class PatchServer : public std::enable_shared_from_this { public: struct Config { bool allow_unregistered_users; bool hide_data_from_logs; uint64_t idle_timeout_usecs; std::string message; std::shared_ptr account_index; std::shared_ptr patch_file_index; std::shared_ptr banned_ipv4_ranges; std::shared_ptr shared_base; }; PatchServer() = delete; explicit PatchServer(std::shared_ptr config); PatchServer(const PatchServer&) = delete; PatchServer(PatchServer&&) = delete; PatchServer& operator=(const PatchServer&) = delete; PatchServer& operator=(PatchServer&&) = delete; virtual ~PatchServer() = default; void schedule_stop(); void wait_for_stop(); void listen(const std::string& addr_str, const std::string& socket_path, Version version); void listen(const std::string& addr_str, const std::string& addr, int port, Version version); void listen(const std::string& addr_str, int port, Version version); void add_socket(const std::string& addr_str, int fd, Version version); void set_config(std::shared_ptr config); private: class Client : public std::enable_shared_from_this { public: std::weak_ptr server; uint64_t id; phosg::PrefixedLogger log; Channel channel; std::vector patch_file_checksum_requests; uint64_t idle_timeout_usecs; std::unique_ptr idle_timeout_event; Client( std::shared_ptr server, struct bufferevent* bev, Version version, uint64_t idle_timeout_usecs, bool hide_data_from_logs); ~Client() = default; void reschedule_timeout_event(); inline Version version() const { return this->channel.version; } static void dispatch_idle_timeout(evutil_socket_t, short, void* ctx); void idle_timeout(); const std::string& get_bb_username() const; void set_bb_username(const std::string& bb_username); }; struct ListeningSocket { std::string addr_str; int fd; Version version; std::unique_ptr listener; ListeningSocket(PatchServer* s, const std::string& name, int fd, Version version); }; std::shared_ptr base; bool base_is_shared; std::shared_ptr config; std::unordered_set> clients_to_destroy; std::shared_ptr destroy_clients_ev; std::unordered_map listening_sockets; std::unordered_map> channel_to_client; std::thread th; void send_server_init(std::shared_ptr c) const; void send_message_box(std::shared_ptr c, const std::string& text) const; void send_enter_directory(std::shared_ptr c, const std::string& dir) const; void change_to_directory( std::shared_ptr c, std::vector& client_path_directories, const std::vector& file_path_directories) const; void on_02(std::shared_ptr c, std::string& data); void on_04(std::shared_ptr c, std::string& data); void on_0F(std::shared_ptr c, std::string& data); void on_10(std::shared_ptr c, std::string& data); void disconnect_client(std::shared_ptr c); void enqueue_destroy_clients(); static void dispatch_destroy_clients(evutil_socket_t, short, void* ctx); static void dispatch_on_listen_accept(struct evconnlistener* listener, evutil_socket_t fd, struct sockaddr* address, int socklen, void* ctx); static void dispatch_on_listen_error(struct evconnlistener* listener, void* ctx); void on_listen_accept(struct evconnlistener* listener, evutil_socket_t fd, struct sockaddr* address, int socklen); void on_listen_error(struct evconnlistener* listener); static void on_client_input(Channel& ch, uint16_t command, uint32_t flag, std::string& data); static void on_client_error(Channel& ch, short events); void thread_fn(); };