#pragma once #include #include #include #include #include #include #include #include #include #include "PSOEncryption.hh" #include "PSOProtocol.hh" #include "ServerState.hh" class ProxyServer { public: ProxyServer() = delete; ProxyServer(const ProxyServer&) = delete; ProxyServer(ProxyServer&&) = delete; ProxyServer( std::shared_ptr base, std::shared_ptr state); virtual ~ProxyServer() = default; void listen(uint16_t port, GameVersion version, const struct sockaddr_storage* default_destination = nullptr); void connect_client(struct bufferevent* bev, uint16_t server_port); struct LinkedSession { ProxyServer* server; uint64_t id; std::string client_name; std::string server_name; PrefixedLogger log; std::unique_ptr timeout_event; std::shared_ptr license; std::unique_ptr client_bev; std::unique_ptr server_bev; uint16_t local_port; struct sockaddr_storage next_destination; uint8_t prev_server_command_bytes[6]; GameVersion version; uint32_t sub_version; std::string character_name; std::string login_command_bb; uint32_t remote_guild_card_number; parray remote_client_config_data; ClientConfigBB newserv_client_config; bool suppress_newserv_commands; bool enable_chat_filter; bool enable_switch_assist; bool save_files; int64_t function_call_return_value; // -1 = don't block function calls G_SwitchStateChanged_6x05 last_switch_enabled_command; int16_t override_section_id; int16_t override_lobby_event; int16_t override_lobby_number; struct LobbyPlayer { uint32_t guild_card_number; std::string name; LobbyPlayer() : guild_card_number(0) { } }; std::vector lobby_players; size_t lobby_client_id; std::shared_ptr client_input_crypt; std::shared_ptr client_output_crypt; std::shared_ptr server_input_crypt; std::shared_ptr server_output_crypt; std::shared_ptr detector_crypt; struct SavingFile { std::string basename; std::string output_filename; uint32_t remaining_bytes; std::unique_ptr> f; SavingFile( const std::string& basename, const std::string& output_filename, uint32_t remaining_bytes); }; std::unordered_map saving_files; // TODO: This first constructor should be private LinkedSession( ProxyServer* server, uint64_t id, uint16_t local_port, GameVersion version); LinkedSession( ProxyServer* server, uint16_t local_port, GameVersion version, std::shared_ptr license, const ClientConfigBB& newserv_client_config); LinkedSession( ProxyServer* server, uint16_t local_port, GameVersion version, std::shared_ptr license, const struct sockaddr_storage& next_destination); LinkedSession( ProxyServer* server, uint64_t id, uint16_t local_port, GameVersion version, const struct sockaddr_storage& next_destination); void resume( std::unique_ptr&& client_bev, std::shared_ptr client_input_crypt, std::shared_ptr client_output_crypt, std::shared_ptr detector_crypt, uint32_t sub_version, const std::string& character_name); void resume( std::unique_ptr&& client_bev, std::shared_ptr client_input_crypt, std::shared_ptr client_output_crypt, std::shared_ptr detector_crypt, std::string&& login_command_bb); void resume(struct bufferevent* client_bev); void resume_inner( std::unique_ptr&& client_bev, std::shared_ptr client_input_crypt, std::shared_ptr client_output_crypt, std::shared_ptr detector_crypt); void connect(); static void dispatch_on_client_input(struct bufferevent* bev, void* ctx); static void dispatch_on_client_error(struct bufferevent* bev, short events, void* ctx); static void dispatch_on_server_input(struct bufferevent* bev, void* ctx); static void dispatch_on_server_error(struct bufferevent* bev, short events, void* ctx); static void dispatch_on_timeout(evutil_socket_t fd, short what, void* ctx); void on_client_input(); void on_server_input(); void on_stream_error(short events, bool is_server_stream); void on_timeout(); void send_to_end(bool to_server, uint16_t command, uint32_t flag, const void* data = nullptr, size_t size = 0); void send_to_end(bool to_server, uint16_t command, uint32_t flag, const std::string& data); void send_to_end_with_header( bool to_server, const void* data, size_t size); void send_to_end_with_header(bool to_server, const std::string& data); void disconnect(); bool is_open() const; }; std::shared_ptr get_session(); std::shared_ptr create_licensed_session( std::shared_ptr l, uint16_t local_port, GameVersion version, const ClientConfigBB& newserv_client_config); void delete_session(uint64_t id); private: struct ListeningSocket { ProxyServer* server; PrefixedLogger log; uint16_t port; scoped_fd fd; std::unique_ptr listener; GameVersion version; struct sockaddr_storage default_destination; ListeningSocket( ProxyServer* server, uint16_t port, GameVersion version, const struct sockaddr_storage* default_destination); 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(int fd); void on_listen_error(); }; struct UnlinkedSession { ProxyServer* server; PrefixedLogger log; std::unique_ptr bev; uint16_t local_port; GameVersion version; struct sockaddr_storage next_destination; std::shared_ptr crypt_out; std::shared_ptr crypt_in; std::shared_ptr detector_crypt; UnlinkedSession(ProxyServer* server, struct bufferevent* bev, uint16_t port, GameVersion version); void receive_and_process_commands(); static void dispatch_on_client_input(struct bufferevent* bev, void* ctx); static void dispatch_on_client_error(struct bufferevent* bev, short events, void* ctx); void on_client_input(); void on_client_error(short events); }; PrefixedLogger log; std::shared_ptr base; std::shared_ptr state; std::map> listeners; std::unordered_map> bev_to_unlinked_session; std::unordered_map> id_to_session; uint64_t next_unlicensed_session_id; void on_client_connect( struct bufferevent* bev, uint16_t listen_port, GameVersion version, const struct sockaddr_storage* default_destination); };