New login process + a little bit of cleanup

No reliability required :) Will get to the client soon
This commit is contained in:
juanjp600
2016-08-31 18:26:17 -03:00
parent d561805010
commit b9a246ca68
4 changed files with 258 additions and 75 deletions
@@ -115,9 +115,6 @@ namespace Barotrauma.Networking
netPeer = client; netPeer = client;
client.Start(); client.Start();
NetOutgoingMessage outmsg = client.CreateMessage();
System.Net.IPEndPoint IPEndPoint = null; System.Net.IPEndPoint IPEndPoint = null;
try try
{ {
@@ -133,7 +130,6 @@ namespace Barotrauma.Networking
// Connect client, to ip previously requested from user // Connect client, to ip previously requested from user
try try
{ {
client.Connect(IPEndPoint, outmsg);
} }
catch (Exception e) catch (Exception e)
@@ -446,11 +442,6 @@ namespace Barotrauma.Networking
public bool SpectateClicked(GUIButton button, object userData) public bool SpectateClicked(GUIButton button, object userData)
{ {
NetOutgoingMessage msg = client.CreateMessage();
client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered);
if (button != null) button.Enabled = false; if (button != null) button.Enabled = false;
return false; return false;
@@ -28,6 +28,8 @@ namespace Barotrauma.Networking
private NetServer server; private NetServer server;
private NetPeerConfiguration config; private NetPeerConfiguration config;
private int MaxPlayers;
private DateTime sparseUpdateTimer; private DateTime sparseUpdateTimer;
private DateTime refreshMasterTimer; private DateTime refreshMasterTimer;
@@ -80,6 +82,7 @@ namespace Barotrauma.Networking
} }
config.MaximumConnections = maxPlayers; config.MaximumConnections = maxPlayers;
MaxPlayers = maxPlayers;
config.DisableMessageType(NetIncomingMessageType.DebugMessage | config.DisableMessageType(NetIncomingMessageType.DebugMessage |
NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt | NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt |
@@ -446,6 +449,16 @@ namespace Barotrauma.Networking
sparseUpdateTimer = DateTime.Now + sparseUpdateInterval; sparseUpdateTimer = DateTime.Now + sparseUpdateInterval;
} }
private byte GetNewClientID()
{
byte userID = 1;
while (connectedClients.Any(c => c.ID == userID))
{
userID++;
}
return userID;
}
public bool StartGameClicked(GUIButton button, object obj) public bool StartGameClicked(GUIButton button, object obj)
{ {
Submarine selectedSub = null; Submarine selectedSub = null;
@@ -13,6 +13,8 @@ namespace Barotrauma.Networking
public NetConnection Connection; public NetConnection Connection;
public int Nonce; public int Nonce;
public int failedAttempts;
public float AuthTimer; public float AuthTimer;
public UnauthenticatedClient(NetConnection connection, int nonce) public UnauthenticatedClient(NetConnection connection, int nonce)
@@ -21,6 +23,8 @@ namespace Barotrauma.Networking
Nonce = nonce; Nonce = nonce;
AuthTimer = 5.0f; AuthTimer = 5.0f;
failedAttempts = 0;
} }
} }
@@ -28,5 +32,163 @@ namespace Barotrauma.Networking
{ {
List<UnauthenticatedClient> unauthenticatedClients = new List<UnauthenticatedClient>(); List<UnauthenticatedClient> unauthenticatedClients = new List<UnauthenticatedClient>();
private void ClientPasswordRequest(NetConnection conn)
{
//client wants to know if server requires password
if (ConnectedClients.Count > MaxPlayers)
{
//server is full, can't allow new connection
conn.Disconnect("Server full");
}
if (ConnectedClients.Find(c => c.Connection == conn) != null)
{
//this client has already been authenticated
return;
}
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.Connection == conn);
if (unauthClient == null)
{
//new client, generate nonce and add to unauth queue
int nonce = CryptoRandom.Instance.Next();
unauthClient = new UnauthenticatedClient(conn, nonce);
unauthenticatedClients.Add(unauthClient);
}
//if the client is already in the queue, getting another unauth request means that our response was lost; resend
NetOutgoingMessage nonceMsg = server.CreateMessage();
if (string.IsNullOrEmpty(password))
{
nonceMsg.Write(false); //false = no password
}
else
{
nonceMsg.Write(true); //true = password
nonceMsg.Write(unauthClient.Nonce); //here's nonce, encrypt with this
}
server.SendMessage(nonceMsg, conn, NetDeliveryMethod.Unreliable);
}
private void ClientInitialize(NetIncomingMessage inc)
{
if (ConnectedClients.Find(c => c.Connection == inc.SenderConnection) != null)
{
//this client was already authenticated
//another init request means they didn't get any update packets yet
return;
}
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.Connection == inc.SenderConnection);
if (unauthClient == null)
{
//client did not ask for nonce first, can't authorize
inc.SenderConnection.Disconnect("Client did not properly request authentication.");
return;
}
if (!string.IsNullOrEmpty(password))
{
//decrypt message and compare password
string saltedPw = password;
saltedPw = saltedPw + Convert.ToString(unauthClient.Nonce);
saltedPw = Encoding.UTF8.GetString(NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(saltedPw)));
NetEncryption algo = new NetXtea(server, saltedPw);
inc.Decrypt(algo);
string clPw = inc.ReadString();
if (clPw != saltedPw)
{
unauthClient.failedAttempts++;
if (unauthClient.failedAttempts > 3)
{
//disconnect after too many failed attempts
unauthClient.Connection.Disconnect("Too many failed login attempts.");
unauthenticatedClients.Remove(unauthClient);
unauthClient = null;
return;
}
else
{
//not disconnecting the player here, because they'll still use the same connection and nonce if they try logging in again
NetOutgoingMessage reject = server.CreateMessage();
reject.Write((byte)ServerPacketHeader.AUTH_FAILURE);
reject.Write("Wrong password!");
server.SendMessage(reject, unauthClient.Connection, NetDeliveryMethod.Unreliable);
return;
}
}
}
string clVersion = inc.ReadString();
string clPackageName = inc.ReadString();
string clPackageHash = inc.ReadString();
if (clVersion != GameMain.Version.ToString())
{
inc.SenderConnection.Disconnect("Version " + GameMain.Version + " required to connect to the server (Your version: " + clVersion + ")");
unauthenticatedClients.Remove(unauthClient);
unauthClient = null;
DebugConsole.NewMessage(name + " couldn't join the server (wrong game version)", Color.Red);
return;
}
if (clPackageName != GameMain.SelectedPackage.Name)
{
inc.SenderConnection.Disconnect("Your content package (" + clPackageName + ") doesn't match the server's version (" + GameMain.SelectedPackage.Name + ")");
unauthenticatedClients.Remove(unauthClient);
unauthClient = null;
DebugConsole.NewMessage(name + " couldn't join the server (wrong content package name)", Color.Red);
return;
}
if (clPackageHash != GameMain.SelectedPackage.MD5hash.Hash)
{
unauthClient.Connection.Disconnect("Your content package (MD5: " + clPackageHash + ") doesn't match the server's version (MD5: " + GameMain.SelectedPackage.MD5hash.Hash + ")");
unauthenticatedClients.Remove(unauthClient);
unauthClient = null;
DebugConsole.NewMessage(name + " couldn't join the server (wrong content package hash)", Color.Red);
return;
}
string clName = Client.SanitizeName(inc.ReadString());
if (string.IsNullOrWhiteSpace(clName))
{
unauthClient.Connection.Disconnect("You need a name.");
unauthenticatedClients.Remove(unauthClient);
unauthClient = null;
return;
}
if (!Client.IsValidName(name))
{
unauthClient.Connection.Disconnect("Your name contains illegal symbols.");
unauthenticatedClients.Remove(unauthClient);
unauthClient = null;
return;
}
Client nameTaken = ConnectedClients.Find(c => c.name.ToLower() == clName.ToLower());
if (nameTaken != null)
{
if (nameTaken.Connection.RemoteEndPoint.Address.ToString() == inc.SenderEndPoint.Address.ToString())
{
//both name and IP address match, replace this player's connection
nameTaken.Connection.Disconnect("Your session was taken by a new connection on the same IP address.");
nameTaken.Connection = unauthClient.Connection;
unauthenticatedClients.Remove(unauthClient);
unauthClient = null;
return;
}
else
{
//can't authorize this client
unauthClient.Connection.Disconnect("That name is taken.");
unauthenticatedClients.Remove(unauthClient);
unauthClient = null;
return;
}
}
//new client
Client newClient = new Client(clName, GetNewClientID());
newClient.Connection = unauthClient.Connection;
unauthenticatedClients.Remove(unauthClient);
unauthClient = null;
return;
}
} }
} }
@@ -9,6 +9,23 @@ using Barotrauma.Items.Components;
namespace Barotrauma.Networking namespace Barotrauma.Networking
{ {
enum ClientPacketHeader
{
REQUEST_AUTH, //ask the server if a password is needed, if so we'll get nonce for encryption
REQUEST_INIT, //ask the server to give you initialization
UPDATE_LOBBY, //update state in lobby
UPDATE_INGAME_ALIVE, //update state ingame while alive (allow character input)
UPDATE_INGAME_SPECTATING, //update state ingame while spectating/dead
}
enum ServerPacketHeader
{
AUTH_RESPONSE, //tell the player if they require a password to log in
AUTH_FAILURE, //the server won't authorize player yet, however connection is still alive
UPDATE_LOBBY, //update state in lobby (votes and chat messages)
UPDATE_INGAME_ALIVE, //update state ingame while alive (character input and chat messages)
UPDATE_INGAME_SPECTATING, //update state ingame while spectating/dead (chat messages)
}
enum VoteType enum VoteType
{ {
Unknown, Unknown,