allow concurrent proxy sessions on the same account

This commit is contained in:
Martin Michelsen
2025-01-06 00:11:28 -08:00
parent 0be056adce
commit 5dbb6c3a27
5 changed files with 64 additions and 20 deletions
+20
View File
@@ -415,6 +415,26 @@ void Account::delete_file() const {
remove(filename.c_str());
}
uint64_t Login::proxy_session_id() const {
uint64_t low_part = 0;
if (this->dc_nte_license) {
low_part = this->dc_nte_license->proxy_session_id_part();
} else if (this->dc_license) {
low_part = this->dc_license->proxy_session_id_part();
} else if (this->pc_license) {
low_part = this->pc_license->proxy_session_id_part();
} else if (this->gc_license) {
low_part = this->gc_license->proxy_session_id_part();
} else if (this->xb_license) {
low_part = this->xb_license->proxy_session_id_part();
} else if (this->bb_license) {
low_part = this->bb_license->proxy_session_id_part();
} else {
throw logic_error("none of the licenses in a Login were present");
}
return (static_cast<uint64_t>(this->account->account_id) << 32) | low_part;
}
string Login::str() const {
string ret = phosg::string_printf("Account:%08" PRIX32, this->account->account_id);
if (this->account_was_created) {
+23
View File
@@ -2,6 +2,7 @@
#include <memory>
#include <mutex>
#include <phosg/Hash.hh>
#include <phosg/JSON.hh>
#include <shared_mutex>
#include <string>
@@ -16,6 +17,10 @@ struct DCNTELicense {
std::string serial_number;
std::string access_key;
inline uint64_t proxy_session_id_part() const {
return phosg::fnv1a32(this->serial_number);
}
static std::shared_ptr<DCNTELicense> from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
@@ -24,6 +29,10 @@ struct V1V2License {
uint32_t serial_number = 0;
std::string access_key;
inline uint64_t proxy_session_id_part() const {
return this->serial_number;
}
static std::shared_ptr<V1V2License> from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
@@ -33,6 +42,10 @@ struct GCLicense {
std::string access_key;
std::string password;
inline uint64_t proxy_session_id_part() const {
return this->serial_number;
}
static std::shared_ptr<GCLicense> from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
@@ -42,6 +55,10 @@ struct XBLicense {
uint64_t user_id = 0;
uint64_t account_id = 0;
inline uint64_t proxy_session_id_part() const {
return phosg::fnv1a32(this->gamertag);
}
static std::shared_ptr<XBLicense> from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
@@ -50,6 +67,10 @@ struct BBLicense {
std::string username;
std::string password;
inline uint64_t proxy_session_id_part() const {
return phosg::fnv1a32(this->username);
}
static std::shared_ptr<BBLicense> from_json(const phosg::JSON& json);
phosg::JSON json() const;
};
@@ -157,6 +178,8 @@ struct Login {
std::shared_ptr<XBLicense> xb_license;
std::shared_ptr<BBLicense> bb_license;
uint64_t proxy_session_id() const;
std::string str() const;
};
+17 -17
View File
@@ -41,8 +41,8 @@ ProxyServer::ProxyServer(
: base(base),
destroy_sessions_ev(event_new(this->base.get(), -1, EV_TIMEOUT, &ProxyServer::dispatch_destroy_sessions, this), event_free),
state(state),
next_unlinked_session_id(this->MIN_UNLINKED_SESSION_ID),
next_logged_out_session_id(this->MIN_LINKED_LOGGED_OUT_SESSION_ID) {}
next_unlinked_session_id(this->FIRST_UNLINKED_SESSION_ID),
next_logged_out_session_id(this->FIRST_LINKED_LOGGED_OUT_SESSION_ID) {}
void ProxyServer::listen(const std::string& addr, uint16_t port, Version version, const struct sockaddr_storage* default_destination) {
auto socket_obj = make_shared<ListeningSocket>(this, addr, port, version, default_destination);
@@ -148,8 +148,8 @@ void ProxyServer::on_client_connect(
// server. This creates a direct session.
if (default_destination && is_patch(version)) {
uint64_t session_id = this->next_logged_out_session_id++;
if (this->next_logged_out_session_id == this->MIN_UNLINKED_SESSION_ID) {
this->next_logged_out_session_id = this->MIN_LINKED_LOGGED_OUT_SESSION_ID;
if (this->next_logged_out_session_id == this->FIRST_LINKED_LOGGED_OUT_SESSION_ID) {
this->next_logged_out_session_id = this->FIRST_LINKED_LOGGED_OUT_SESSION_ID;
}
auto emplace_ret = this->id_to_linked_session.emplace(session_id, make_shared<LinkedSession>(this->shared_from_this(), session_id, listen_port, version, *default_destination));
@@ -167,8 +167,8 @@ void ProxyServer::on_client_connect(
// create an unlinked session - we'll have to get the destination from the
// client's config, which we'll get via a 9E command soon.
uint64_t session_id = this->next_unlinked_session_id++;
if (this->next_unlinked_session_id == 0) {
this->next_unlinked_session_id = this->MIN_UNLINKED_SESSION_ID;
if (this->next_unlinked_session_id == this->FIRST_LINKED_LOGGED_OUT_SESSION_ID) {
this->next_unlinked_session_id = this->FIRST_UNLINKED_SESSION_ID;
}
auto emplace_ret = this->id_to_unlinked_session.emplace(
@@ -445,7 +445,7 @@ void ProxyServer::UnlinkedSession::on_input(Channel& ch, uint16_t command, uint3
// Look up the linked session for this account (if any)
shared_ptr<LinkedSession> linked_ses;
try {
linked_ses = server->id_to_linked_session.at(ses->login->account->account_id);
linked_ses = server->id_to_linked_session.at(ses->login->proxy_session_id());
linked_ses->log.info("Resuming linked session from unlinked session");
} catch (const out_of_range&) {
@@ -464,7 +464,7 @@ void ProxyServer::UnlinkedSession::on_input(Channel& ch, uint16_t command, uint3
}
if (linked_ses.get()) {
server->id_to_linked_session.emplace(ses->login->account->account_id, linked_ses);
server->id_to_linked_session.emplace(linked_ses->id, linked_ses);
// Resume the linked session using the unlinked session
try {
if (ses->version() == Version::BB_V4) {
@@ -514,7 +514,7 @@ ProxyServer::LinkedSession::LinkedSession(
Version version)
: server(server),
id(id),
log(phosg::string_printf("[ProxyServer:LS-%" PRIX64 "] ", this->id), proxy_server_log.min_level),
log(phosg::string_printf("[ProxyServer:LS-%016" PRIX64 "] ", this->id), proxy_server_log.min_level),
timeout_event(event_new(server->base.get(), -1, EV_TIMEOUT, &LinkedSession::dispatch_on_timeout, this), event_free),
login(nullptr),
client_channel(
@@ -523,7 +523,7 @@ ProxyServer::LinkedSession::LinkedSession(
nullptr,
nullptr,
this,
phosg::string_printf("LS-%" PRIX64 "-C", this->id),
phosg::string_printf("LS-%016" PRIX64 "-C", this->id),
phosg::TerminalFormat::FG_YELLOW,
phosg::TerminalFormat::FG_GREEN),
server_channel(
@@ -532,7 +532,7 @@ ProxyServer::LinkedSession::LinkedSession(
nullptr,
nullptr,
this,
phosg::string_printf("LS-%" PRIX64 "-S", this->id),
phosg::string_printf("LS-%016" PRIX64 "-S", this->id),
phosg::TerminalFormat::FG_YELLOW,
phosg::TerminalFormat::FG_RED),
local_port(local_port),
@@ -564,7 +564,7 @@ ProxyServer::LinkedSession::LinkedSession(
Version version,
shared_ptr<Login> login,
const Client::Config& config)
: LinkedSession(server, login->account->account_id, local_port, version) {
: LinkedSession(server, login->proxy_session_id(), local_port, version) {
this->login = login;
this->config = config;
memset(&this->next_destination, 0, sizeof(this->next_destination));
@@ -580,7 +580,7 @@ ProxyServer::LinkedSession::LinkedSession(
Version version,
std::shared_ptr<Login> login,
const struct sockaddr_storage& next_destination)
: LinkedSession(server, login->account->account_id, local_port, version) {
: LinkedSession(server, login->proxy_session_id(), local_port, version) {
this->login = login;
this->next_destination = next_destination;
}
@@ -707,8 +707,8 @@ void ProxyServer::LinkedSession::update_channel_names() {
auto client_ip_str = s->format_address_for_channel_name(
this->client_channel.remote_addr, this->client_channel.virtual_network_id);
auto server_ip_str = s->format_address_for_channel_name(this->server_channel.remote_addr, 0);
this->client_channel.name = phosg::string_printf("LS-%08" PRIX64 "-C @ %s", this->id, client_ip_str.c_str());
this->server_channel.name = phosg::string_printf("LS-%08" PRIX64 "-S @ %s", this->id, server_ip_str.c_str());
this->client_channel.name = phosg::string_printf("LS-%016" PRIX64 "-C @ %s", this->id, client_ip_str.c_str());
this->server_channel.name = phosg::string_printf("LS-%016" PRIX64 "-S @ %s", this->id, server_ip_str.c_str());
}
ProxyServer::LinkedSession::SavingFile::SavingFile(
@@ -991,9 +991,9 @@ shared_ptr<ProxyServer::LinkedSession> ProxyServer::create_logged_in_session(
}
void ProxyServer::delete_session(uint64_t id) {
if (id < this->MIN_UNLINKED_SESSION_ID) {
if (id >= this->FIRST_LINKED_LOGGED_OUT_SESSION_ID) {
if (this->id_to_linked_session.erase(id)) {
proxy_server_log.info("Closed LS-%08" PRIX64, id);
proxy_server_log.info("Closed LS-%016" PRIX64, id);
}
} else {
auto it = this->id_to_unlinked_session.find(id);
+3 -2
View File
@@ -307,6 +307,7 @@ private:
Version version,
const struct sockaddr_storage* default_destination);
static constexpr uint64_t MIN_UNLINKED_SESSION_ID = 0xC000000000000000;
static constexpr uint64_t MIN_LINKED_LOGGED_OUT_SESSION_ID = 0x1000000000000000;
static constexpr uint64_t FIRST_UNLINKED_SESSION_ID = 0x0000000000000001;
static constexpr uint64_t FIRST_LINKED_LOGGED_OUT_SESSION_ID = 0x0000000080000000;
static constexpr uint64_t FIRST_LINKED_LOGGED_IN_SESSION_ID = 0x00000000FFFFFFFF;
};
+1 -1
View File
@@ -250,7 +250,7 @@ void send_client_to_proxy_server(shared_ptr<Client> c) {
string port_name = proxy_port_name_for_version(c->version());
uint16_t local_port = s->name_to_port_config.at(port_name)->port;
s->proxy_server->delete_session(c->login->account->account_id);
s->proxy_server->delete_session(c->login->proxy_session_id());
auto ses = s->proxy_server->create_logged_in_session(c->login, local_port, c->version(), c->config);
if (!c->can_use_chat_commands()) {
ses->config.clear_flag(Client::Flag::PROXY_CHAT_COMMANDS_ENABLED);