diff --git a/Core/ClientConnectionData.h b/Core/ClientConnectionData.h
index 632566cd..0df67f05 100644
--- a/Core/ClientConnectionData.h
+++ b/Core/ClientConnectionData.h
@@ -7,13 +7,14 @@ class ClientConnectionData
public:
string Host;
uint16_t Port;
-
+ string Password;
string PlayerName;
-
bool Spectator;
- ClientConnectionData(string host, uint16_t port, string playerName, bool spectator) :
- Host(host), Port(port), PlayerName(playerName), Spectator(spectator)
+ ClientConnectionData() {}
+
+ ClientConnectionData(string host, uint16_t port, string password, string playerName, bool spectator) :
+ Host(host), Port(port), Password(password), PlayerName(playerName), Spectator(spectator)
{
}
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 94f79764..0f202033 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -531,6 +531,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 28bda578..cefa5e79 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -1372,6 +1372,9 @@
Misc
+
+ NetPlay\Messages
+
diff --git a/Core/GameClient.cpp b/Core/GameClient.cpp
index d41eff82..c46d96c8 100644
--- a/Core/GameClient.cpp
+++ b/Core/GameClient.cpp
@@ -33,7 +33,7 @@ bool GameClient::Connected()
return instance ? instance->_connected : false;
}
-void GameClient::Connect(shared_ptr connectionData)
+void GameClient::Connect(ClientConnectionData &connectionData)
{
_instance.reset(new GameClient());
@@ -55,11 +55,11 @@ shared_ptr GameClient::GetConnection()
return instance ? instance->_connection : nullptr;
}
-void GameClient::PrivateConnect(shared_ptr connectionData)
+void GameClient::PrivateConnect(ClientConnectionData &connectionData)
{
_stop = false;
shared_ptr socket(new Socket());
- if(socket->Connect(connectionData->Host.c_str(), connectionData->Port)) {
+ if(socket->Connect(connectionData.Host.c_str(), connectionData.Port)) {
_connection.reset(new GameClientConnection(socket, connectionData));
_connected = true;
} else {
diff --git a/Core/GameClient.h b/Core/GameClient.h
index ef081149..8ef0af1d 100644
--- a/Core/GameClient.h
+++ b/Core/GameClient.h
@@ -19,7 +19,7 @@ private:
static shared_ptr GetConnection();
- void PrivateConnect(shared_ptr connectionData);
+ void PrivateConnect(ClientConnectionData &connectionData);
void Exec();
public:
@@ -27,7 +27,7 @@ public:
virtual ~GameClient();
static bool Connected();
- static void Connect(shared_ptr connectionData);
+ static void Connect(ClientConnectionData &connectionData);
static void Disconnect();
static void SelectController(uint8_t port);
diff --git a/Core/GameClientConnection.cpp b/Core/GameClientConnection.cpp
index 50088de7..54015830 100644
--- a/Core/GameClientConnection.cpp
+++ b/Core/GameClientConnection.cpp
@@ -16,9 +16,11 @@
#include "SelectControllerMessage.h"
#include "PlayerListMessage.h"
#include "ForceDisconnectMessage.h"
+#include "ServerInformationMessage.h"
-GameClientConnection::GameClientConnection(shared_ptr socket, shared_ptr connectionData) : GameConnection(socket, connectionData)
+GameClientConnection::GameClientConnection(shared_ptr socket, ClientConnectionData &connectionData) : GameConnection(socket)
{
+ _connectionData = connectionData;
_shutdown = false;
_enableControllers = false;
_minimumQueueSize = 3;
@@ -26,7 +28,6 @@ GameClientConnection::GameClientConnection(shared_ptr socket, shared_ptr
MessageManager::RegisterNotificationListener(this);
MessageManager::DisplayMessage("NetPlay", "ConnectedToServer");
ControlManager::RegisterInputProvider(this);
- SendHandshake();
}
GameClientConnection::~GameClientConnection()
@@ -50,7 +51,7 @@ void GameClientConnection::Shutdown()
void GameClientConnection::SendHandshake()
{
- HandShakeMessage message(_connectionData->PlayerName, _connectionData->Spectator);
+ HandShakeMessage message(_connectionData.PlayerName, HandShakeMessage::GetPasswordHash(_connectionData.Password, _serverSalt), _connectionData.Spectator);
SendNetMessage(message);
}
@@ -74,6 +75,11 @@ void GameClientConnection::ProcessMessage(NetMessage* message)
GameInformationMessage* gameInfo;
switch(message->GetType()) {
+ case MessageType::ServerInformation:
+ _serverSalt = ((ServerInformationMessage*)message)->GetHashSalt();
+ SendHandshake();
+ break;
+
case MessageType::SaveState:
if(_gameLoaded) {
DisableControllers();
diff --git a/Core/GameClientConnection.h b/Core/GameClientConnection.h
index 3a51ab74..a8faf824 100644
--- a/Core/GameClientConnection.h
+++ b/Core/GameClientConnection.h
@@ -7,8 +7,7 @@
#include "BaseControlDevice.h"
#include "IInputProvider.h"
#include "ControlDeviceState.h"
-
-class ClientConnectionData;
+#include "ClientConnectionData.h"
class GameClientConnection : public GameConnection, public INotificationListener, public IInputProvider
{
@@ -28,6 +27,8 @@ private:
ControlDeviceState _lastInputSent;
bool _gameLoaded = false;
uint8_t _controllerPort = GameConnection::SpectatorPort;
+ ClientConnectionData _connectionData;
+ string _serverSalt;
private:
void SendHandshake();
@@ -40,7 +41,7 @@ protected:
void ProcessMessage(NetMessage* message) override;
public:
- GameClientConnection(shared_ptr socket, shared_ptr connectionData);
+ GameClientConnection(shared_ptr socket, ClientConnectionData &connectionData);
virtual ~GameClientConnection();
void Shutdown();
diff --git a/Core/GameConnection.cpp b/Core/GameConnection.cpp
index efa9d152..e9069c48 100644
--- a/Core/GameConnection.cpp
+++ b/Core/GameConnection.cpp
@@ -9,12 +9,12 @@
#include "SelectControllerMessage.h"
#include "ClientConnectionData.h"
#include "ForceDisconnectMessage.h"
+#include "ServerInformationMessage.h"
const uint32_t PlayerListMessage::PlayerNameMaxLength;
-GameConnection::GameConnection(shared_ptr socket, shared_ptr connectionData)
+GameConnection::GameConnection(shared_ptr socket)
{
- _connectionData = connectionData;
_socket = socket;
}
@@ -64,6 +64,7 @@ NetMessage* GameConnection::ReadMessage()
case MessageType::PlayerList: return new PlayerListMessage(_messageBuffer, messageLength);
case MessageType::SelectController: return new SelectControllerMessage(_messageBuffer, messageLength);
case MessageType::ForceDisconnect: return new ForceDisconnectMessage(_messageBuffer, messageLength);
+ case MessageType::ServerInformation: return new ServerInformationMessage(_messageBuffer, messageLength);
}
}
}
diff --git a/Core/GameConnection.h b/Core/GameConnection.h
index a7dfa72f..b4e3642e 100644
--- a/Core/GameConnection.h
+++ b/Core/GameConnection.h
@@ -4,7 +4,6 @@
class Socket;
class NetMessage;
-class ClientConnectionData;
struct PlayerInfo
{
@@ -17,7 +16,6 @@ class GameConnection
{
protected:
shared_ptr _socket;
- shared_ptr _connectionData;
uint8_t _readBuffer[0x40000] = {};
uint8_t _messageBuffer[0x40000] = {};
int _readPosition = 0;
@@ -36,7 +34,7 @@ protected:
public:
static const uint8_t SpectatorPort = 0xFF;
- GameConnection(shared_ptr socket, shared_ptr connectionData);
+ GameConnection(shared_ptr socket);
bool ConnectionError();
void ProcessMessages();
diff --git a/Core/GameServer.cpp b/Core/GameServer.cpp
index c4946662..08d5d79b 100644
--- a/Core/GameServer.cpp
+++ b/Core/GameServer.cpp
@@ -11,10 +11,11 @@ using std::thread;
unique_ptr GameServer::Instance;
-GameServer::GameServer(uint16_t listenPort, string hostPlayerName)
+GameServer::GameServer(uint16_t listenPort, string password, string hostPlayerName)
{
_stop = false;
_port = listenPort;
+ _password = password;
_hostPlayerName = hostPlayerName;
_hostControllerPort = 0;
ControlManager::RegisterInputRecorder(this);
@@ -37,7 +38,7 @@ void GameServer::AcceptConnections()
while(true) {
shared_ptr socket = _listener->Accept();
if(!socket->ConnectionError()) {
- _openConnections.push_back(shared_ptr(new GameServerConnection(socket)));
+ _openConnections.push_back(shared_ptr(new GameServerConnection(socket, _password)));
} else {
break;
}
@@ -121,9 +122,9 @@ void GameServer::Stop()
MessageManager::DisplayMessage("NetPlay", "ServerStopped");
}
-void GameServer::StartServer(uint16_t port, string hostPlayerName)
+void GameServer::StartServer(uint16_t port, string password, string hostPlayerName)
{
- Instance.reset(new GameServer(port, hostPlayerName));
+ Instance.reset(new GameServer(port, password, hostPlayerName));
Instance->_serverThread.reset(new thread(&GameServer::Exec, Instance.get()));
}
diff --git a/Core/GameServer.h b/Core/GameServer.h
index d5e49147..781f1a34 100644
--- a/Core/GameServer.h
+++ b/Core/GameServer.h
@@ -17,6 +17,7 @@ private:
unique_ptr _listener;
uint16_t _port;
+ string _password;
list> _openConnections;
bool _initialized = false;
@@ -30,10 +31,10 @@ private:
void Stop();
public:
- GameServer(uint16_t port, string hostPlayerName);
+ GameServer(uint16_t port, string password, string hostPlayerName);
virtual ~GameServer();
- static void StartServer(uint16_t port, string hostPlayerName);
+ static void StartServer(uint16_t port, string password, string hostPlayerName);
static void StopServer();
static bool Started();
diff --git a/Core/GameServerConnection.cpp b/Core/GameServerConnection.cpp
index 2bc89931..f668e2b3 100644
--- a/Core/GameServerConnection.cpp
+++ b/Core/GameServerConnection.cpp
@@ -1,4 +1,5 @@
#include "stdafx.h"
+#include
#include "MessageManager.h"
#include "GameServerConnection.h"
#include "HandShakeMessage.h"
@@ -16,26 +17,46 @@
#include "GameServer.h"
#include "ForceDisconnectMessage.h"
#include "BaseControlDevice.h"
+#include "ServerInformationMessage.h"
GameServerConnection* GameServerConnection::_netPlayDevices[BaseControlDevice::PortCount] = { };
-GameServerConnection::GameServerConnection(shared_ptr socket) : GameConnection(socket, nullptr)
+GameServerConnection::GameServerConnection(shared_ptr socket, string serverPassword) : GameConnection(socket)
{
//Server-side connection
+ _serverPassword = serverPassword;
_controllerPort = GameConnection::SpectatorPort;
MessageManager::RegisterNotificationListener(this);
+ SendServerInformation();
}
GameServerConnection::~GameServerConnection()
{
- if(_connectionData) {
- MessageManager::DisplayMessage("NetPlay", _connectionData->PlayerName + " (Player " + std::to_string(_controllerPort + 1) + ") disconnected.");
+ if(!_playerName.empty()) {
+ MessageManager::DisplayMessage("NetPlay", _playerName + " (Player " + std::to_string(_controllerPort + 1) + ") disconnected.");
}
UnregisterNetPlayDevice(this);
MessageManager::UnregisterNotificationListener(this);
}
+void GameServerConnection::SendServerInformation()
+{
+ std::random_device rd;
+ std::mt19937 engine(rd());
+ std::uniform_int_distribution<> dist((int)' ', (int)'~');
+ string hash(50, ' ');
+ for(int i = 0; i < 50; i++) {
+ int random = dist(engine);
+ hash[i] = (char)random;
+ }
+
+ _connectionHash = hash;
+
+ ServerInformationMessage message(hash);
+ SendNetMessage(message);
+}
+
void GameServerConnection::SendGameInformation()
{
Console::Pause();
@@ -88,23 +109,27 @@ void GameServerConnection::ProcessHandshakeResponse(HandShakeMessage* message)
{
//Send the game's current state to the client and register the controller
if(message->IsValid()) {
- Console::Pause();
+ if(message->CheckPassword(_serverPassword, _connectionHash)) {
+ Console::Pause();
- _controllerPort = message->IsSpectator() ? GameConnection::SpectatorPort : GetFirstFreeControllerPort();
- _connectionData.reset(new ClientConnectionData("", 0, message->GetPlayerName(), false));
+ _controllerPort = message->IsSpectator() ? GameConnection::SpectatorPort : GetFirstFreeControllerPort();
+ _playerName = message->GetPlayerName();
- string playerPortMessage = _controllerPort == GameConnection::SpectatorPort ? "Spectator" : "Player " + std::to_string(_controllerPort + 1);
+ string playerPortMessage = _controllerPort == GameConnection::SpectatorPort ? "Spectator" : "Player " + std::to_string(_controllerPort + 1);
- MessageManager::DisplayMessage("NetPlay", _connectionData->PlayerName + " (" + playerPortMessage + ") connected.");
+ MessageManager::DisplayMessage("NetPlay", _playerName + " (" + playerPortMessage + ") connected.");
- if(Console::GetMapperInfo().RomName.size() > 0) {
- SendGameInformation();
+ if(Console::GetMapperInfo().RomName.size() > 0) {
+ SendGameInformation();
+ }
+
+ _handshakeCompleted = true;
+ RegisterNetPlayDevice(this, _controllerPort);
+ GameServer::SendPlayerList();
+ Console::Resume();
+ } else {
+ SendForceDisconnectMessage("The password you provided did not match - you have been disconnected.");
}
-
- _handshakeCompleted = true;
- RegisterNetPlayDevice(this, _controllerPort);
- GameServer::SendPlayerList();
- Console::Resume();
} else {
SendForceDisconnectMessage("Server is using a different version of Mesen (" + EmulationSettings::GetMesenVersionString() + ") - you have been disconnected.");
MessageManager::DisplayMessage("NetPlay", + "NetplayVersionMismatch", message->GetPlayerName());
@@ -119,10 +144,16 @@ void GameServerConnection::ProcessMessage(NetMessage* message)
break;
case MessageType::InputData:
+ if(_handshakeCompleted) {
+ break;
+ }
PushState(((InputDataMessage*)message)->GetInputState());
break;
case MessageType::SelectController:
+ if(_handshakeCompleted) {
+ break;
+ }
SelectControllerPort(((SelectControllerMessage*)message)->GetPortNumber());
break;
@@ -208,11 +239,7 @@ uint8_t GameServerConnection::GetFirstFreeControllerPort()
string GameServerConnection::GetPlayerName()
{
- if(_connectionData) {
- return _connectionData->PlayerName;
- } else {
- return "";
- }
+ return _playerName;
}
uint8_t GameServerConnection::GetControllerPort()
diff --git a/Core/GameServerConnection.h b/Core/GameServerConnection.h
index 7c80387d..1f560479 100644
--- a/Core/GameServerConnection.h
+++ b/Core/GameServerConnection.h
@@ -15,10 +15,14 @@ private:
static GameServerConnection* _netPlayDevices[BaseControlDevice::PortCount];
list _inputData;
+ string _playerName;
int _controllerPort;
+ string _connectionHash;
+ string _serverPassword;
bool _handshakeCompleted = false;
void PushState(ControlDeviceState state);
+ void SendServerInformation();
void SendGameInformation();
void SelectControllerPort(uint8_t port);
@@ -34,7 +38,7 @@ protected:
void ProcessMessage(NetMessage* message) override;
public:
- GameServerConnection(shared_ptr socket);
+ GameServerConnection(shared_ptr socket, string serverPassword);
virtual ~GameServerConnection();
ControlDeviceState GetState();
diff --git a/Core/HandShakeMessage.h b/Core/HandShakeMessage.h
index 64f5feca..ce61e480 100644
--- a/Core/HandShakeMessage.h
+++ b/Core/HandShakeMessage.h
@@ -2,33 +2,38 @@
#include "stdafx.h"
#include "NetMessage.h"
#include "EmulationSettings.h"
+#include "../Utilities/sha1.h"
class HandShakeMessage : public NetMessage
{
private:
- const static int CurrentVersion = 1;
+ const static int CurrentVersion = 2;
uint32_t _mesenVersion = 0;
uint32_t _protocolVersion = CurrentVersion;
char* _playerName = nullptr;
uint32_t _playerNameLength = 0;
+ char* _hashedPassword = nullptr;
+ uint32_t _hashedPasswordLength = 0;
bool _spectator = false;
-
+
protected:
virtual void ProtectedStreamState()
{
Stream(_mesenVersion);
Stream(_protocolVersion);
StreamArray((void**)&_playerName, _playerNameLength);
+ StreamArray((void**)&_hashedPassword, _hashedPasswordLength);
Stream(_spectator);
}
public:
- HandShakeMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) { }
- HandShakeMessage(string playerName, bool spectator) : NetMessage(MessageType::HandShake)
+ HandShakeMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) {}
+ HandShakeMessage(string playerName, string hashedPassword, bool spectator) : NetMessage(MessageType::HandShake)
{
_mesenVersion = EmulationSettings::GetMesenVersion();
_protocolVersion = HandShakeMessage::CurrentVersion;
CopyString(&_playerName, _playerNameLength, playerName);
+ CopyString(&_hashedPassword, _hashedPasswordLength, hashedPassword);
_spectator = spectator;
}
@@ -42,8 +47,20 @@ public:
return _protocolVersion == CurrentVersion && _mesenVersion == EmulationSettings::GetMesenVersion();
}
+ bool CheckPassword(string serverPassword, string connectionHash)
+ {
+ return GetPasswordHash(serverPassword, connectionHash) == string(_hashedPassword);
+ }
+
bool IsSpectator()
{
return _spectator;
}
+
+ static string GetPasswordHash(string serverPassword, string connectionHash)
+ {
+ string saltedPassword = serverPassword + connectionHash;
+ vector dataToHash = vector(saltedPassword.c_str(), saltedPassword.c_str() + saltedPassword.size());
+ return SHA1::GetHash(dataToHash);
+ }
};
diff --git a/Core/MessageType.h b/Core/MessageType.h
index 901e244e..c1318cc3 100644
--- a/Core/MessageType.h
+++ b/Core/MessageType.h
@@ -10,5 +10,6 @@ enum class MessageType : uint8_t
GameInformation = 4,
PlayerList = 5,
SelectController = 6,
- ForceDisconnect = 7
+ ForceDisconnect = 7,
+ ServerInformation = 8
};
\ No newline at end of file
diff --git a/Core/ServerInformationMessage.h b/Core/ServerInformationMessage.h
new file mode 100644
index 00000000..fd14f3ae
--- /dev/null
+++ b/Core/ServerInformationMessage.h
@@ -0,0 +1,28 @@
+#pragma once
+#include "stdafx.h"
+#include "NetMessage.h"
+
+class ServerInformationMessage : public NetMessage
+{
+private:
+ char* _hashSalt = nullptr;
+ uint32_t _hashSaltLength = 0;
+
+protected:
+ virtual void ProtectedStreamState()
+ {
+ StreamArray((void**)&_hashSalt, _hashSaltLength);
+ }
+
+public:
+ ServerInformationMessage(void* buffer, uint32_t length) : NetMessage(buffer, length) {}
+ ServerInformationMessage(string hashSalt) : NetMessage(MessageType::ServerInformation)
+ {
+ CopyString(&_hashSalt, _hashSaltLength, hashSalt);
+ }
+
+ string GetHashSalt()
+ {
+ return string(_hashSalt);
+ }
+};
diff --git a/GUI.NET/Config/ClientConnection.cs b/GUI.NET/Config/ClientConnection.cs
index bd7f9887..cb1ea5eb 100644
--- a/GUI.NET/Config/ClientConnection.cs
+++ b/GUI.NET/Config/ClientConnection.cs
@@ -10,6 +10,7 @@ namespace Mesen.GUI.Config
{
public string Host = "localhost";
public UInt16 Port = 8888;
+ public string Password = "";
public bool Spectator = false;
}
}
diff --git a/GUI.NET/Config/ServerInfo.cs b/GUI.NET/Config/ServerInfo.cs
index 23be52fa..1c7cd2a4 100644
--- a/GUI.NET/Config/ServerInfo.cs
+++ b/GUI.NET/Config/ServerInfo.cs
@@ -10,9 +10,6 @@ namespace Mesen.GUI.Config
{
public string Name = "Default";
public UInt16 Port = 8888;
- public string Password = null;
- public int MaxPlayers = 4;
- public bool AllowSpectators = true;
- public bool PublicServer = false;
+ public string Password = "";
}
}
diff --git a/GUI.NET/Controls/MesenNumericUpDown.cs b/GUI.NET/Controls/MesenNumericUpDown.cs
index 857e593a..1057bb40 100644
--- a/GUI.NET/Controls/MesenNumericUpDown.cs
+++ b/GUI.NET/Controls/MesenNumericUpDown.cs
@@ -159,9 +159,9 @@ namespace Mesen.GUI.Controls
set { _minimum = value; SetValue(this.Value, true); }
}
- public decimal Increment { get; set; }
+ public decimal Increment { get; set; } = 1;
- private int _decimalPlaces = 2;
+ private int _decimalPlaces = 0;
public int DecimalPlaces
{
get { return _decimalPlaces; }
diff --git a/GUI.NET/Dependencies/resources.ca.xml b/GUI.NET/Dependencies/resources.ca.xml
index 5f37e4a9..e91e2167 100644
--- a/GUI.NET/Dependencies/resources.ca.xml
+++ b/GUI.NET/Dependencies/resources.ca.xml
@@ -440,6 +440,7 @@