network: check Console ID conflicts
As Console ID can be sensitive data sometimes, this implementation sent a SHA256 hash of it instead.
This commit is contained in:
parent
3c589f473f
commit
c396e3c6e5
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 6e27aa4c8671e183f11e327a2e1f556c64fdc4a9
|
|
@ -39,6 +39,7 @@
|
||||||
#include "core/frontend/applets/default_applets.h"
|
#include "core/frontend/applets/default_applets.h"
|
||||||
#include "core/gdbstub/gdbstub.h"
|
#include "core/gdbstub/gdbstub.h"
|
||||||
#include "core/hle/service/am/am.h"
|
#include "core/hle/service/am/am.h"
|
||||||
|
#include "core/hle/service/cfg/cfg.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
#include "core/movie.h"
|
#include "core/movie.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
|
@ -336,7 +337,8 @@ int main(int argc, char** argv) {
|
||||||
member->BindOnStateChanged(OnStateChanged);
|
member->BindOnStateChanged(OnStateChanged);
|
||||||
LOG_DEBUG(Network, "Start connection to {}:{} with nickname {}", address, port,
|
LOG_DEBUG(Network, "Start connection to {}:{} with nickname {}", address, port,
|
||||||
nickname);
|
nickname);
|
||||||
member->Join(nickname, address.c_str(), port, 0, Network::NoPreferredMac, password);
|
member->Join(nickname, Service::CFG::GetConsoleIdHash(system), address.c_str(), port, 0,
|
||||||
|
Network::NoPreferredMac, password);
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR(Network, "Could not access RoomMember");
|
LOG_ERROR(Network, "Could not access RoomMember");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "citra_qt/multiplayer/state.h"
|
#include "citra_qt/multiplayer/state.h"
|
||||||
#include "citra_qt/multiplayer/validation.h"
|
#include "citra_qt/multiplayer/validation.h"
|
||||||
#include "citra_qt/ui_settings.h"
|
#include "citra_qt/ui_settings.h"
|
||||||
|
#include "core/hle/service/cfg/cfg.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
#include "ui_direct_connect.h"
|
#include "ui_direct_connect.h"
|
||||||
|
@ -97,6 +98,7 @@ void DirectConnectWindow::Connect() {
|
||||||
if (auto room_member = Network::GetRoomMember().lock()) {
|
if (auto room_member = Network::GetRoomMember().lock()) {
|
||||||
auto port = UISettings::values.port.toUInt();
|
auto port = UISettings::values.port.toUInt();
|
||||||
room_member->Join(ui->nickname->text().toStdString(),
|
room_member->Join(ui->nickname->text().toStdString(),
|
||||||
|
Service::CFG::GetConsoleIdHash(Core::System::GetInstance()),
|
||||||
ui->ip->text().toStdString().c_str(), port, 0,
|
ui->ip->text().toStdString().c_str(), port, 0,
|
||||||
Network::NoPreferredMac, ui->password->text().toStdString().c_str());
|
Network::NoPreferredMac, ui->password->text().toStdString().c_str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "citra_qt/ui_settings.h"
|
#include "citra_qt/ui_settings.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/announce_multiplayer_session.h"
|
#include "core/announce_multiplayer_session.h"
|
||||||
|
#include "core/hle/service/cfg/cfg.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "ui_host_room.h"
|
#include "ui_host_room.h"
|
||||||
|
|
||||||
|
@ -116,8 +117,9 @@ void HostRoomWindow::Host() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
member->Join(ui->username->text().toStdString(), "127.0.0.1", port, 0,
|
member->Join(ui->username->text().toStdString(),
|
||||||
Network::NoPreferredMac, password);
|
Service::CFG::GetConsoleIdHash(Core::System::GetInstance()), "127.0.0.1", port,
|
||||||
|
0, Network::NoPreferredMac, password);
|
||||||
|
|
||||||
// Store settings
|
// Store settings
|
||||||
UISettings::values.room_nickname = ui->username->text();
|
UISettings::values.room_nickname = ui->username->text();
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "citra_qt/multiplayer/validation.h"
|
#include "citra_qt/multiplayer/validation.h"
|
||||||
#include "citra_qt/ui_settings.h"
|
#include "citra_qt/ui_settings.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "core/hle/service/cfg/cfg.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
|
|
||||||
|
@ -139,7 +140,8 @@ void Lobby::OnJoinRoom(const QModelIndex& source) {
|
||||||
// attempt to connect in a different thread
|
// attempt to connect in a different thread
|
||||||
QFuture<void> f = QtConcurrent::run([nickname, ip, port, password] {
|
QFuture<void> f = QtConcurrent::run([nickname, ip, port, password] {
|
||||||
if (auto room_member = Network::GetRoomMember().lock()) {
|
if (auto room_member = Network::GetRoomMember().lock()) {
|
||||||
room_member->Join(nickname, ip.c_str(), port, 0, Network::NoPreferredMac, password);
|
room_member->Join(nickname, Service::CFG::GetConsoleIdHash(Core::System::GetInstance()),
|
||||||
|
ip.c_str(), port, 0, Network::NoPreferredMac, password);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
watcher->setFuture(f);
|
watcher->setFuture(f);
|
||||||
|
|
|
@ -38,6 +38,9 @@ const ConnectionError GENERIC_ERROR(
|
||||||
const ConnectionError LOST_CONNECTION(QT_TR_NOOP("Connection to room lost. Try to reconnect."));
|
const ConnectionError LOST_CONNECTION(QT_TR_NOOP("Connection to room lost. Try to reconnect."));
|
||||||
const ConnectionError MAC_COLLISION(
|
const ConnectionError MAC_COLLISION(
|
||||||
QT_TR_NOOP("MAC address is already in use. Please choose another."));
|
QT_TR_NOOP("MAC address is already in use. Please choose another."));
|
||||||
|
const ConnectionError CONSOLE_ID_COLLISION(QT_TR_NOOP(
|
||||||
|
"Your Console ID conflicted with someone else's in the room.\n\nPlease go to Emulation "
|
||||||
|
"> Configure > System to regenerate your Console ID."));
|
||||||
|
|
||||||
static bool WarnMessage(const std::string& title, const std::string& text) {
|
static bool WarnMessage(const std::string& title, const std::string& text) {
|
||||||
return QMessageBox::Ok == QMessageBox::warning(nullptr, QObject::tr(title.c_str()),
|
return QMessageBox::Ok == QMessageBox::warning(nullptr, QObject::tr(title.c_str()),
|
||||||
|
|
|
@ -37,6 +37,7 @@ extern const ConnectionError WRONG_PASSWORD;
|
||||||
extern const ConnectionError GENERIC_ERROR;
|
extern const ConnectionError GENERIC_ERROR;
|
||||||
extern const ConnectionError LOST_CONNECTION;
|
extern const ConnectionError LOST_CONNECTION;
|
||||||
extern const ConnectionError MAC_COLLISION;
|
extern const ConnectionError MAC_COLLISION;
|
||||||
|
extern const ConnectionError CONSOLE_ID_COLLISION;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a standard QMessageBox with a error message
|
* Shows a standard QMessageBox with a error message
|
||||||
|
|
|
@ -102,6 +102,9 @@ void MultiplayerState::OnNetworkStateChanged(const Network::RoomMember::State& s
|
||||||
case Network::RoomMember::State::MacCollision:
|
case Network::RoomMember::State::MacCollision:
|
||||||
NetworkMessage::ShowError(NetworkMessage::MAC_COLLISION);
|
NetworkMessage::ShowError(NetworkMessage::MAC_COLLISION);
|
||||||
break;
|
break;
|
||||||
|
case Network::RoomMember::State::ConsoleIdCollision:
|
||||||
|
NetworkMessage::ShowError(NetworkMessage::CONSOLE_ID_COLLISION);
|
||||||
|
break;
|
||||||
case Network::RoomMember::State::RoomIsFull:
|
case Network::RoomMember::State::RoomIsFull:
|
||||||
NetworkMessage::ShowError(NetworkMessage::ROOM_IS_FULL);
|
NetworkMessage::ShowError(NetworkMessage::ROOM_IS_FULL);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -734,4 +734,21 @@ void InstallInterfaces(Core::System& system) {
|
||||||
std::make_shared<CFG_NOR>()->InstallAsService(service_manager);
|
std::make_shared<CFG_NOR>()->InstallAsService(service_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetConsoleIdHash(Core::System& system) {
|
||||||
|
u64_le console_id{};
|
||||||
|
std::array<u8, sizeof(console_id)> buffer;
|
||||||
|
if (system.IsPoweredOn()) {
|
||||||
|
auto cfg = GetModule(system);
|
||||||
|
ASSERT_MSG(cfg, "CFG Module missing!");
|
||||||
|
console_id = cfg->GetConsoleUniqueId();
|
||||||
|
} else {
|
||||||
|
console_id = std::make_unique<Service::CFG::Module>()->GetConsoleUniqueId();
|
||||||
|
}
|
||||||
|
std::memcpy(buffer.data(), &console_id, sizeof(console_id));
|
||||||
|
|
||||||
|
std::array<u8, CryptoPP::SHA256::DIGESTSIZE> hash;
|
||||||
|
CryptoPP::SHA256().CalculateDigest(hash.data(), buffer.data(), sizeof(buffer));
|
||||||
|
return fmt::format("{:02x}", fmt::join(hash.begin(), hash.end(), ""));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Service::CFG
|
} // namespace Service::CFG
|
||||||
|
|
|
@ -415,4 +415,7 @@ std::shared_ptr<Module> GetModule(Core::System& system);
|
||||||
|
|
||||||
void InstallInterfaces(Core::System& system);
|
void InstallInterfaces(Core::System& system);
|
||||||
|
|
||||||
|
/// Convenience function for getting a SHA256 hash of the Console ID
|
||||||
|
std::string GetConsoleIdHash(Core::System& system);
|
||||||
|
|
||||||
} // namespace Service::CFG
|
} // namespace Service::CFG
|
||||||
|
|
|
@ -31,10 +31,11 @@ public:
|
||||||
std::string password; ///< The password required to connect to this room.
|
std::string password; ///< The password required to connect to this room.
|
||||||
|
|
||||||
struct Member {
|
struct Member {
|
||||||
std::string nickname; ///< The nickname of the member.
|
std::string nickname; ///< The nickname of the member.
|
||||||
GameInfo game_info; ///< The current game of the member
|
std::string console_id_hash; ///< A hash of the console ID of the member.
|
||||||
MacAddress mac_address; ///< The assigned mac address of the member.
|
GameInfo game_info; ///< The current game of the member
|
||||||
ENetPeer* peer; ///< The remote peer.
|
MacAddress mac_address; ///< The assigned mac address of the member.
|
||||||
|
ENetPeer* peer; ///< The remote peer.
|
||||||
};
|
};
|
||||||
using MemberList = std::vector<Member>;
|
using MemberList = std::vector<Member>;
|
||||||
MemberList members; ///< Information about the members of this room
|
MemberList members; ///< Information about the members of this room
|
||||||
|
@ -69,6 +70,12 @@ public:
|
||||||
*/
|
*/
|
||||||
bool IsValidMacAddress(const MacAddress& address) const;
|
bool IsValidMacAddress(const MacAddress& address) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the console ID (hash) is valid, ie. isn't already taken by someone else in
|
||||||
|
* the room.
|
||||||
|
*/
|
||||||
|
bool IsValidConsoleId(const std::string& console_id_hash) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a ID_ROOM_IS_FULL message telling the client that the room is full.
|
* Sends a ID_ROOM_IS_FULL message telling the client that the room is full.
|
||||||
*/
|
*/
|
||||||
|
@ -84,6 +91,12 @@ public:
|
||||||
*/
|
*/
|
||||||
void SendMacCollision(ENetPeer* client);
|
void SendMacCollision(ENetPeer* client);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a IdConsoleIdCollison message telling the client that another member with the same
|
||||||
|
* console ID exists.
|
||||||
|
*/
|
||||||
|
void SendConsoleIdCollision(ENetPeer* client);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a ID_ROOM_VERSION_MISMATCH message telling the client that the version is invalid.
|
* Sends a ID_ROOM_VERSION_MISMATCH message telling the client that the version is invalid.
|
||||||
*/
|
*/
|
||||||
|
@ -212,6 +225,9 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
|
||||||
std::string nickname;
|
std::string nickname;
|
||||||
packet >> nickname;
|
packet >> nickname;
|
||||||
|
|
||||||
|
std::string console_id_hash;
|
||||||
|
packet >> console_id_hash;
|
||||||
|
|
||||||
MacAddress preferred_mac;
|
MacAddress preferred_mac;
|
||||||
packet >> preferred_mac;
|
packet >> preferred_mac;
|
||||||
|
|
||||||
|
@ -242,6 +258,11 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
|
||||||
preferred_mac = GenerateMacAddress();
|
preferred_mac = GenerateMacAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!IsValidConsoleId(console_id_hash)) {
|
||||||
|
SendConsoleIdCollision(event->peer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (client_version != network_version) {
|
if (client_version != network_version) {
|
||||||
SendVersionMismatch(event->peer);
|
SendVersionMismatch(event->peer);
|
||||||
return;
|
return;
|
||||||
|
@ -250,6 +271,7 @@ void Room::RoomImpl::HandleJoinRequest(const ENetEvent* event) {
|
||||||
// At this point the client is ready to be added to the room.
|
// At this point the client is ready to be added to the room.
|
||||||
Member member{};
|
Member member{};
|
||||||
member.mac_address = preferred_mac;
|
member.mac_address = preferred_mac;
|
||||||
|
member.console_id_hash = console_id_hash;
|
||||||
member.nickname = nickname;
|
member.nickname = nickname;
|
||||||
member.peer = event->peer;
|
member.peer = event->peer;
|
||||||
|
|
||||||
|
@ -282,6 +304,14 @@ bool Room::RoomImpl::IsValidMacAddress(const MacAddress& address) const {
|
||||||
[&address](const auto& member) { return member.mac_address != address; });
|
[&address](const auto& member) { return member.mac_address != address; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Room::RoomImpl::IsValidConsoleId(const std::string& console_id_hash) const {
|
||||||
|
// A Console ID is valid if it is not already taken by anybody else in the room.
|
||||||
|
std::lock_guard<std::mutex> lock(member_mutex);
|
||||||
|
return std::all_of(members.begin(), members.end(), [&console_id_hash](const auto& member) {
|
||||||
|
return member.console_id_hash != console_id_hash;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void Room::RoomImpl::SendNameCollision(ENetPeer* client) {
|
void Room::RoomImpl::SendNameCollision(ENetPeer* client) {
|
||||||
Packet packet;
|
Packet packet;
|
||||||
packet << static_cast<u8>(IdNameCollision);
|
packet << static_cast<u8>(IdNameCollision);
|
||||||
|
@ -302,6 +332,16 @@ void Room::RoomImpl::SendMacCollision(ENetPeer* client) {
|
||||||
enet_host_flush(server);
|
enet_host_flush(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Room::RoomImpl::SendConsoleIdCollision(ENetPeer* client) {
|
||||||
|
Packet packet;
|
||||||
|
packet << static_cast<u8>(IdConsoleIdCollision);
|
||||||
|
|
||||||
|
ENetPacket* enet_packet =
|
||||||
|
enet_packet_create(packet.GetData(), packet.GetDataSize(), ENET_PACKET_FLAG_RELIABLE);
|
||||||
|
enet_peer_send(client, 0, enet_packet);
|
||||||
|
enet_host_flush(server);
|
||||||
|
}
|
||||||
|
|
||||||
void Room::RoomImpl::SendWrongPassword(ENetPeer* client) {
|
void Room::RoomImpl::SendWrongPassword(ENetPeer* client) {
|
||||||
Packet packet;
|
Packet packet;
|
||||||
packet << static_cast<u8>(IdWrongPassword);
|
packet << static_cast<u8>(IdWrongPassword);
|
||||||
|
|
|
@ -59,6 +59,7 @@ enum RoomMessageTypes : u8 {
|
||||||
IdWrongPassword,
|
IdWrongPassword,
|
||||||
IdCloseRoom,
|
IdCloseRoom,
|
||||||
IdRoomIsFull,
|
IdRoomIsFull,
|
||||||
|
IdConsoleIdCollision,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This is what a server [person creating a server] would use.
|
/// This is what a server [person creating a server] would use.
|
||||||
|
|
|
@ -73,11 +73,12 @@ public:
|
||||||
* Sends a request to the server, asking for permission to join a room with the specified
|
* Sends a request to the server, asking for permission to join a room with the specified
|
||||||
* nickname and preferred mac.
|
* nickname and preferred mac.
|
||||||
* @params nickname The desired nickname.
|
* @params nickname The desired nickname.
|
||||||
|
* @params console_id_hash A hash of the Console ID.
|
||||||
* @params preferred_mac The preferred MAC address to use in the room, the NoPreferredMac tells
|
* @params preferred_mac The preferred MAC address to use in the room, the NoPreferredMac tells
|
||||||
* @params password The password for the room
|
* @params password The password for the room
|
||||||
* the server to assign one for us.
|
* the server to assign one for us.
|
||||||
*/
|
*/
|
||||||
void SendJoinRequest(const std::string& nickname,
|
void SendJoinRequest(const std::string& nickname, const std::string& console_id_hash,
|
||||||
const MacAddress& preferred_mac = NoPreferredMac,
|
const MacAddress& preferred_mac = NoPreferredMac,
|
||||||
const std::string& password = "");
|
const std::string& password = "");
|
||||||
|
|
||||||
|
@ -163,6 +164,9 @@ void RoomMember::RoomMemberImpl::MemberLoop() {
|
||||||
case IdMacCollision:
|
case IdMacCollision:
|
||||||
SetState(State::MacCollision);
|
SetState(State::MacCollision);
|
||||||
break;
|
break;
|
||||||
|
case IdConsoleIdCollision:
|
||||||
|
SetState(State::ConsoleIdCollision);
|
||||||
|
break;
|
||||||
case IdVersionMismatch:
|
case IdVersionMismatch:
|
||||||
SetState(State::WrongVersion);
|
SetState(State::WrongVersion);
|
||||||
break;
|
break;
|
||||||
|
@ -204,11 +208,13 @@ void RoomMember::RoomMemberImpl::Send(Packet&& packet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname,
|
void RoomMember::RoomMemberImpl::SendJoinRequest(const std::string& nickname,
|
||||||
|
const std::string& console_id_hash,
|
||||||
const MacAddress& preferred_mac,
|
const MacAddress& preferred_mac,
|
||||||
const std::string& password) {
|
const std::string& password) {
|
||||||
Packet packet;
|
Packet packet;
|
||||||
packet << static_cast<u8>(IdJoinRequest);
|
packet << static_cast<u8>(IdJoinRequest);
|
||||||
packet << nickname;
|
packet << nickname;
|
||||||
|
packet << console_id_hash;
|
||||||
packet << preferred_mac;
|
packet << preferred_mac;
|
||||||
packet << network_version;
|
packet << network_version;
|
||||||
packet << password;
|
packet << password;
|
||||||
|
@ -392,9 +398,9 @@ RoomInformation RoomMember::GetRoomInformation() const {
|
||||||
return room_member_impl->room_information;
|
return room_member_impl->room_information;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoomMember::Join(const std::string& nick, const char* server_addr, u16 server_port,
|
void RoomMember::Join(const std::string& nick, const std::string& console_id_hash,
|
||||||
u16 client_port, const MacAddress& preferred_mac,
|
const char* server_addr, u16 server_port, u16 client_port,
|
||||||
const std::string& password) {
|
const MacAddress& preferred_mac, const std::string& password) {
|
||||||
// If the member is connected, kill the connection first
|
// If the member is connected, kill the connection first
|
||||||
if (room_member_impl->loop_thread && room_member_impl->loop_thread->joinable()) {
|
if (room_member_impl->loop_thread && room_member_impl->loop_thread->joinable()) {
|
||||||
Leave();
|
Leave();
|
||||||
|
@ -427,7 +433,7 @@ void RoomMember::Join(const std::string& nick, const char* server_addr, u16 serv
|
||||||
if (net > 0 && event.type == ENET_EVENT_TYPE_CONNECT) {
|
if (net > 0 && event.type == ENET_EVENT_TYPE_CONNECT) {
|
||||||
room_member_impl->nickname = nick;
|
room_member_impl->nickname = nick;
|
||||||
room_member_impl->StartLoop();
|
room_member_impl->StartLoop();
|
||||||
room_member_impl->SendJoinRequest(nick, preferred_mac, password);
|
room_member_impl->SendJoinRequest(nick, console_id_hash, preferred_mac, password);
|
||||||
SendGameInfo(room_member_impl->current_game_info);
|
SendGameInfo(room_member_impl->current_game_info);
|
||||||
} else {
|
} else {
|
||||||
enet_peer_disconnect(room_member_impl->server, 0);
|
enet_peer_disconnect(room_member_impl->server, 0);
|
||||||
|
|
|
@ -54,12 +54,13 @@ public:
|
||||||
LostConnection, ///< Connection closed
|
LostConnection, ///< Connection closed
|
||||||
|
|
||||||
// Reasons why connection was rejected
|
// Reasons why connection was rejected
|
||||||
NameCollision, ///< Somebody is already using this name
|
NameCollision, ///< Somebody is already using this name
|
||||||
MacCollision, ///< Somebody is already using that mac-address
|
MacCollision, ///< Somebody is already using that mac-address
|
||||||
WrongVersion, ///< The room version is not the same as for this RoomMember
|
ConsoleIdCollision, ///< Somebody in the room has the same Console ID
|
||||||
WrongPassword, ///< The password doesn't match the one from the Room
|
WrongVersion, ///< The room version is not the same as for this RoomMember
|
||||||
CouldNotConnect, ///< The room is not responding to a connection attempt
|
WrongPassword, ///< The password doesn't match the one from the Room
|
||||||
RoomIsFull ///< Room is already at the maximum number of players
|
CouldNotConnect, ///< The room is not responding to a connection attempt
|
||||||
|
RoomIsFull ///< Room is already at the maximum number of players
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MemberInformation {
|
struct MemberInformation {
|
||||||
|
@ -116,11 +117,13 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to join a room at the specified address and port, using the specified nickname.
|
* Attempts to join a room at the specified address and port, using the specified nickname.
|
||||||
* This may fail if the username is already taken.
|
* A console ID hash is passed in to check console ID conflicts.
|
||||||
|
* This may fail if the username or console ID is already taken.
|
||||||
*/
|
*/
|
||||||
void Join(const std::string& nickname, const char* server_addr = "127.0.0.1",
|
void Join(const std::string& nickname, const std::string& console_id_hash,
|
||||||
const u16 server_port = DefaultRoomPort, const u16 client_port = 0,
|
const char* server_addr = "127.0.0.1", const u16 server_port = DefaultRoomPort,
|
||||||
const MacAddress& preferred_mac = NoPreferredMac, const std::string& password = "");
|
const u16 client_port = 0, const MacAddress& preferred_mac = NoPreferredMac,
|
||||||
|
const std::string& password = "");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a WiFi packet to the room.
|
* Sends a WiFi packet to the room.
|
||||||
|
|
Reference in New Issue