diff --git a/protocol.md b/protocol.md
index 847d676..eae0c43 100644
--- a/protocol.md
+++ b/protocol.md
@@ -283,19 +283,31 @@ Communication between the master server and clients will be done over a WebSocke
2 |
Message |
String |
- R1 |
+ ¬R1 |
2 |
Session Id |
Packed Unsigned Long |
- ¬R1 |
+ R1 |
3 |
Secret |
Bytes (16) |
- ¬R1 |
+ R1 |
+
+
+ 4 |
+ Server Address |
+ IPv4 String |
+ R1 |
+
+
+ 5 |
+ Server Port |
+ Packed Unsigned Short |
+ R1 |
@@ -345,25 +357,15 @@ Communication between the master server and clients will be done over a WebSocke
Iterated over n (0 ≤ i ≤ n - 1) |
- 2 + 4i |
+ 2 + 2i |
Server Id |
Packed Unsigned Short |
- 3 + 4i |
+ 3 + 2i |
User Count |
Packed Unsigned Short |
-
- 4 + 4i |
- IP Address |
- IPv4 String |
-
-
- 5 + 4i |
- Port |
- Packed Unsigned Short |
-
#### Client to Master
@@ -409,6 +411,11 @@ Communication between the master server and clients will be done over a WebSocke
Password |
String |
+
+ 3 |
+ Server Id |
+ Packed Unsigned Short |
+
diff --git a/server/DAL/Session.cs b/server/DAL/Session.cs
index c49767e..cf867ef 100644
--- a/server/DAL/Session.cs
+++ b/server/DAL/Session.cs
@@ -17,6 +17,13 @@ namespace SockScape.DAL {
[Required, Index(IsUnique = true)]
public byte[] Secret { get; set; }
+ [Required]
+ public DateTime LastPing { get; set; }
+
+ [NotMapped]
+ public TimeSpan DeltaLastPing
+ => DateTime.UtcNow - LastPing;
+
[Required]
public int ServerId { get; set; }
}
diff --git a/server/Libraries/Kneesocks/Connection.cs b/server/Libraries/Kneesocks/Connection.cs
index c8ad887..241c7be 100644
--- a/server/Libraries/Kneesocks/Connection.cs
+++ b/server/Libraries/Kneesocks/Connection.cs
@@ -171,9 +171,9 @@ namespace Kneesocks {
internal void Parse() {
if(Handshaked) {
if(!Buffer.IsReading) {
- if(TimeSinceLastPing.Seconds > TimeoutInterval) {
+ if(TimeSinceLastPing.TotalSeconds > TimeoutInterval) {
Disconnect(Frame.kClosingReason.Normal, "Ping response timed out.");
- } else if(TimeSinceLastPing.Seconds > PingInterval && !AwaitingPingResponse) {
+ } else if(TimeSinceLastPing.TotalSeconds > PingInterval && !AwaitingPingResponse) {
var frameBytes = new Frame {
IsFinal = true,
IsMasked = false,
@@ -204,7 +204,7 @@ namespace Kneesocks {
if(Buffer.IsReading) {
readBuffer = Buffer.AttemptRead();
if(readBuffer == null) {
- if((!Handshaked || (Handshaked && FirstTwoBytes != null)) && Buffer.ElapsedReadTime.Seconds > (Handshaked ? 300 : 30))
+ if((!Handshaked || (Handshaked && FirstTwoBytes != null)) && Buffer.ElapsedReadTime.TotalSeconds > (Handshaked ? 300 : 30))
Disconnect(Frame.kClosingReason.ProtocolError, "Timed out waiting for a full response");
return;
diff --git a/server/MasterServerList.cs b/server/MasterServerList.cs
index c1cc0d1..28af288 100644
--- a/server/MasterServerList.cs
+++ b/server/MasterServerList.cs
@@ -36,8 +36,7 @@ namespace SockScape {
var packet = new Packet(kInterMasterId.ServerListing, ((ushort)_Servers.Count).Pack());
foreach(var server in _Servers)
// TODO change this to support IPv6
- packet.AddRegions(server.Key.Pack(), server.Value.UserCount.Pack(),
- server.Value.Address.MapToIPv4().ToString(), server.Value.Port.Pack());
+ packet.AddRegions(server.Key.Pack(), server.Value.UserCount.Pack());
return packet;
}
@@ -47,7 +46,7 @@ namespace SockScape {
public static void RemoveServersByOwners(IEnumerable owners) {
lock(_Servers) {
_Servers = _Servers.Where(x => !owners.Contains(x.Value.Owner))
- .ToDictionary(x => x.Key, x => x.Value);
+ .ToDictionary(x => x.Key, x => x.Value);
}
}
diff --git a/server/Socks/MasterConnection.cs b/server/Socks/MasterConnection.cs
index 91afbc0..99ab89d 100644
--- a/server/Socks/MasterConnection.cs
+++ b/server/Socks/MasterConnection.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Text;
@@ -16,7 +17,7 @@ namespace SockScape {
protected override void OnOpen() {
Key = new Key();
- Send(Key.GenerateRequestPacket().GetBytes());
+ Send(Key.GenerateRequestPacket());
}
protected override void OnParse() {
@@ -49,11 +50,44 @@ namespace SockScape {
Encryptor = new StreamCipher(Key.PrivateKey);
break;
case kInterMasterId.LoginAttempt:
- if(packet.RegionCount != 2)
+ if(packet.RegionCount != 3 || !packet.CheckRegions(2, 2))
break;
using(var db = new ScapeDb()) {
- if(db.Users.)
+ User user;
+ if((user = db.Users.FirstOrDefault(x => x.Username == packet[0])) == null) {
+ SendEncrypted(new Packet(kInterMasterId.LoginAttempt, Convert.ToByte(false), "User does not exist."));
+ break;
+ }
+
+ if(!packet[1].Str.CheckPassword(user.Password)) {
+ SendEncrypted(new Packet(kInterMasterId.LoginAttempt, Convert.ToByte(false), "Password is incorrect."));
+ break;
+ }
+
+ if(user.Session?.DeltaLastPing.TotalMinutes < 3) {
+ SendEncrypted(new Packet(kInterMasterId.LoginAttempt, Convert.ToByte(false), "You are already logged in. Log out or try again shortly."));
+ break;
+ }
+
+ ushort server = packet[2].Raw.UnpackUInt16();
+ if(!MasterServerList.HasId(server)) {
+ SendEncrypted(new Packet(kInterMasterId.LoginAttempt, Convert.ToByte(false), "The world you have specified is offline."));
+ break;
+ }
+
+ if(user.Session?.DeltaLastPing.TotalMinutes >= 3) {
+ db.Entry(user.Session).State = EntityState.Deleted;
+ db.SaveChanges();
+ }
+
+ db.Sessions.Add(new Session {
+ Id = user.Id,
+ Secret = RNG.NextBytes(16),
+ ServerId = server,
+ LastPing = DateTime.UtcNow
+ });
+ db.SaveChanges();
}
break;
case kInterMasterId.RegistrationAttempt:
@@ -68,5 +102,13 @@ namespace SockScape {
Console.WriteLine($"{Id} says {data.GetString()}");
}
+
+ private void Send(Packet packet) {
+ Send(packet.GetBytes());
+ }
+
+ private void SendEncrypted(Packet packet) {
+ Send(Encryptor.Parse(packet.GetBytes()));
+ }
}
}
diff --git a/server/Socks/MasterIntraClient.cs b/server/Socks/MasterIntraClient.cs
index ca1a0c1..c980d42 100644
--- a/server/Socks/MasterIntraClient.cs
+++ b/server/Socks/MasterIntraClient.cs
@@ -20,11 +20,11 @@ namespace SockScape {
private static DateTime LastMessageOut = new DateTime(0);
private static TimeSpan DeltaLastOut
- => DateTime.Now - LastMessageOut;
+ => DateTime.UtcNow - LastMessageOut;
private static DateTime LastMessageIn = new DateTime(0);
private static TimeSpan DeltaLastIn
- => DateTime.Now - LastMessageIn;
+ => DateTime.UtcNow - LastMessageIn;
public static void Initialize() {
if(IsOpen || ListeningThread != null)
@@ -52,7 +52,7 @@ namespace SockScape {
var endPoint = new IPEndPoint(IPAddress.Any, 0);
while(Sock.Available > 0) {
var data = Sock.Receive(ref endPoint);
- LastMessageIn = DateTime.Now;
+ LastMessageIn = DateTime.UtcNow;
bool readRaw = Encryptor == null
|| data.Take(Packet.MagicNumber.Length).SequenceEqual(Packet.MagicNumber);
@@ -108,7 +108,7 @@ namespace SockScape {
public static void Send(byte[] bytes) {
Sock.Send(bytes, bytes.Length);
- LastMessageOut = DateTime.Now;
+ LastMessageOut = DateTime.UtcNow;
}
public static void Close() {
diff --git a/server/Socks/MasterIntraServer.cs b/server/Socks/MasterIntraServer.cs
index 0856164..d253134 100644
--- a/server/Socks/MasterIntraServer.cs
+++ b/server/Socks/MasterIntraServer.cs
@@ -63,9 +63,9 @@ namespace SockScape {
}
if(IsProspectConnected(client) && encryptor == null)
- Prospects[client].LastReceive = DateTime.Now;
+ Prospects[client].LastReceive = DateTime.UtcNow;
else if(IsClientConnected(client) && encryptor != null)
- Clients[client].LastReceive = DateTime.Now;
+ Clients[client].LastReceive = DateTime.UtcNow;
switch((kIntraSlaveId)packet.Id) {
case kIntraSlaveId.InitiationAttempt:
@@ -75,7 +75,7 @@ namespace SockScape {
if(packet[0] == Configuration.General["Master Secret"]) {
var key = new Key();
Prospects[client] = new Client {
- LastReceive = DateTime.Now,
+ LastReceive = DateTime.UtcNow,
Address = endPoint,
Key = key
};
@@ -90,7 +90,7 @@ namespace SockScape {
var privateKey = Prospects[client].Key.ParseResponsePacket(packet);
if(privateKey != -1) {
- Prospects[client].LastReceive = DateTime.Now;
+ Prospects[client].LastReceive = DateTime.UtcNow;
Prospects[client].Encryptor = new BlockCipher(privateKey);
Clients[client] = Prospects[client];
Prospects.Remove(client);
@@ -131,10 +131,10 @@ namespace SockScape {
}
}
- Prospects = Prospects.Where(x => x.Value.ReceiveDelta.Seconds < 10)
+ Prospects = Prospects.Where(x => x.Value.ReceiveDelta.TotalSeconds < 10)
.ToDictionary(x => x.Key, x => x.Value);
- var expiredClients = Clients.Where(x => x.Value.ReceiveDelta.Seconds > 60).Select(x => x.Value).ToList();
+ var expiredClients = Clients.Where(x => x.Value.ReceiveDelta.TotalSeconds > 60).Select(x => x.Value).ToList();
if(expiredClients.Count > 0)
MasterServerList.RemoveServersByOwners(expiredClients);
@@ -180,7 +180,7 @@ namespace SockScape {
public class Client {
public IPEndPoint Address { get; set; }
public DateTime LastReceive { get; set; }
- public TimeSpan ReceiveDelta => DateTime.Now - LastReceive;
+ public TimeSpan ReceiveDelta => DateTime.UtcNow - LastReceive;
public BlockCipher Encryptor { get; set; }
public Key Key { get; set; }
}
diff --git a/server/Socks/PlayerConnection.cs b/server/Socks/PlayerConnection.cs
index 567548c..4bce3b4 100644
--- a/server/Socks/PlayerConnection.cs
+++ b/server/Socks/PlayerConnection.cs
@@ -17,7 +17,7 @@ namespace SockScape {
}
protected override void OnParse() {
- if((DateTime.UtcNow - ConnectionOpened).Seconds > 60) {
+ if((DateTime.UtcNow - ConnectionOpened).TotalSeconds > 60) {
Disconnect(Frame.kClosingReason.ProtocolError, "Logon request timed out.");
}
}