VACUUM DOT MATRIX MONTHLY
note on my desk
This commit is contained in:
parent
4b1adda2a6
commit
978977282d
8 changed files with 91 additions and 36 deletions
37
protocol.md
37
protocol.md
|
@ -283,19 +283,31 @@ Communication between the master server and clients will be done over a WebSocke
|
||||||
<td class="center">2</td>
|
<td class="center">2</td>
|
||||||
<td>Message</td>
|
<td>Message</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
<td>R<sub>1</sub></td>
|
<td>¬R<sub>1</sub></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="center">2</td>
|
<td class="center">2</td>
|
||||||
<td>Session Id</td>
|
<td>Session Id</td>
|
||||||
<td>Packed Unsigned Long</td>
|
<td>Packed Unsigned Long</td>
|
||||||
<td>¬R<sub>1</sub></td>
|
<td>R<sub>1</sub></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="center">3</td>
|
<td class="center">3</td>
|
||||||
<td>Secret</td>
|
<td>Secret</td>
|
||||||
<td>Bytes (16)</td>
|
<td>Bytes (16)</td>
|
||||||
<td>¬R<sub>1</sub></td>
|
<td>R<sub>1</sub></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="center">4</td>
|
||||||
|
<td>Server Address</td>
|
||||||
|
<td>IPv4 String</td>
|
||||||
|
<td>R<sub>1</sub></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="center">5</td>
|
||||||
|
<td>Server Port</td>
|
||||||
|
<td>Packed Unsigned Short</td>
|
||||||
|
<td>R<sub>1</sub></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@ -345,25 +357,15 @@ Communication between the master server and clients will be done over a WebSocke
|
||||||
<td colspan="2">Iterated over <i>n</i> (0 ≤ <i>i</i> ≤ <i>n - 1</i>)</td>
|
<td colspan="2">Iterated over <i>n</i> (0 ≤ <i>i</i> ≤ <i>n - 1</i>)</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="center">2 + 4<i>i</i></td>
|
<td class="center">2 + 2<i>i</i></td>
|
||||||
<td>Server Id</td>
|
<td>Server Id</td>
|
||||||
<td>Packed Unsigned Short</td>
|
<td>Packed Unsigned Short</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="center">3 + 4<i>i</i></td>
|
<td class="center">3 + 2<i>i</i></td>
|
||||||
<td>User Count</td>
|
<td>User Count</td>
|
||||||
<td>Packed Unsigned Short</td>
|
<td>Packed Unsigned Short</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td class="center">4 + 4<i>i</i></td>
|
|
||||||
<td>IP Address</td>
|
|
||||||
<td>IPv4 String</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td class="center">5 + 4<i>i</i></td>
|
|
||||||
<td>Port</td>
|
|
||||||
<td>Packed Unsigned Short</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
#### Client to Master
|
#### Client to Master
|
||||||
|
@ -409,6 +411,11 @@ Communication between the master server and clients will be done over a WebSocke
|
||||||
<td>Password</td>
|
<td>Password</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="center">3</td>
|
||||||
|
<td>Server Id</td>
|
||||||
|
<td>Packed Unsigned Short</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<table style="margin-right: 8px; margin-bottom: 8px;">
|
<table style="margin-right: 8px; margin-bottom: 8px;">
|
||||||
|
|
|
@ -17,6 +17,13 @@ namespace SockScape.DAL {
|
||||||
[Required, Index(IsUnique = true)]
|
[Required, Index(IsUnique = true)]
|
||||||
public byte[] Secret { get; set; }
|
public byte[] Secret { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public DateTime LastPing { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public TimeSpan DeltaLastPing
|
||||||
|
=> DateTime.UtcNow - LastPing;
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public int ServerId { get; set; }
|
public int ServerId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,9 +171,9 @@ namespace Kneesocks {
|
||||||
internal void Parse() {
|
internal void Parse() {
|
||||||
if(Handshaked) {
|
if(Handshaked) {
|
||||||
if(!Buffer.IsReading) {
|
if(!Buffer.IsReading) {
|
||||||
if(TimeSinceLastPing.Seconds > TimeoutInterval) {
|
if(TimeSinceLastPing.TotalSeconds > TimeoutInterval) {
|
||||||
Disconnect(Frame.kClosingReason.Normal, "Ping response timed out.");
|
Disconnect(Frame.kClosingReason.Normal, "Ping response timed out.");
|
||||||
} else if(TimeSinceLastPing.Seconds > PingInterval && !AwaitingPingResponse) {
|
} else if(TimeSinceLastPing.TotalSeconds > PingInterval && !AwaitingPingResponse) {
|
||||||
var frameBytes = new Frame {
|
var frameBytes = new Frame {
|
||||||
IsFinal = true,
|
IsFinal = true,
|
||||||
IsMasked = false,
|
IsMasked = false,
|
||||||
|
@ -204,7 +204,7 @@ namespace Kneesocks {
|
||||||
if(Buffer.IsReading) {
|
if(Buffer.IsReading) {
|
||||||
readBuffer = Buffer.AttemptRead();
|
readBuffer = Buffer.AttemptRead();
|
||||||
if(readBuffer == null) {
|
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");
|
Disconnect(Frame.kClosingReason.ProtocolError, "Timed out waiting for a full response");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -36,8 +36,7 @@ namespace SockScape {
|
||||||
var packet = new Packet(kInterMasterId.ServerListing, ((ushort)_Servers.Count).Pack());
|
var packet = new Packet(kInterMasterId.ServerListing, ((ushort)_Servers.Count).Pack());
|
||||||
foreach(var server in _Servers)
|
foreach(var server in _Servers)
|
||||||
// TODO change this to support IPv6
|
// TODO change this to support IPv6
|
||||||
packet.AddRegions(server.Key.Pack(), server.Value.UserCount.Pack(),
|
packet.AddRegions(server.Key.Pack(), server.Value.UserCount.Pack());
|
||||||
server.Value.Address.MapToIPv4().ToString(), server.Value.Port.Pack());
|
|
||||||
|
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
@ -47,7 +46,7 @@ namespace SockScape {
|
||||||
public static void RemoveServersByOwners(IEnumerable<MasterIntraServer.Client> owners) {
|
public static void RemoveServersByOwners(IEnumerable<MasterIntraServer.Client> owners) {
|
||||||
lock(_Servers) {
|
lock(_Servers) {
|
||||||
_Servers = _Servers.Where(x => !owners.Contains(x.Value.Owner))
|
_Servers = _Servers.Where(x => !owners.Contains(x.Value.Owner))
|
||||||
.ToDictionary(x => x.Key, x => x.Value);
|
.ToDictionary(x => x.Key, x => x.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Entity;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
@ -16,7 +17,7 @@ namespace SockScape {
|
||||||
|
|
||||||
protected override void OnOpen() {
|
protected override void OnOpen() {
|
||||||
Key = new Key();
|
Key = new Key();
|
||||||
Send(Key.GenerateRequestPacket().GetBytes());
|
Send(Key.GenerateRequestPacket());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnParse() {
|
protected override void OnParse() {
|
||||||
|
@ -49,11 +50,44 @@ namespace SockScape {
|
||||||
Encryptor = new StreamCipher(Key.PrivateKey);
|
Encryptor = new StreamCipher(Key.PrivateKey);
|
||||||
break;
|
break;
|
||||||
case kInterMasterId.LoginAttempt:
|
case kInterMasterId.LoginAttempt:
|
||||||
if(packet.RegionCount != 2)
|
if(packet.RegionCount != 3 || !packet.CheckRegions(2, 2))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
using(var db = new ScapeDb()) {
|
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;
|
break;
|
||||||
case kInterMasterId.RegistrationAttempt:
|
case kInterMasterId.RegistrationAttempt:
|
||||||
|
@ -68,5 +102,13 @@ namespace SockScape {
|
||||||
|
|
||||||
Console.WriteLine($"{Id} says {data.GetString()}");
|
Console.WriteLine($"{Id} says {data.GetString()}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Send(Packet packet) {
|
||||||
|
Send(packet.GetBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendEncrypted(Packet packet) {
|
||||||
|
Send(Encryptor.Parse(packet.GetBytes()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,11 @@ namespace SockScape {
|
||||||
|
|
||||||
private static DateTime LastMessageOut = new DateTime(0);
|
private static DateTime LastMessageOut = new DateTime(0);
|
||||||
private static TimeSpan DeltaLastOut
|
private static TimeSpan DeltaLastOut
|
||||||
=> DateTime.Now - LastMessageOut;
|
=> DateTime.UtcNow - LastMessageOut;
|
||||||
|
|
||||||
private static DateTime LastMessageIn = new DateTime(0);
|
private static DateTime LastMessageIn = new DateTime(0);
|
||||||
private static TimeSpan DeltaLastIn
|
private static TimeSpan DeltaLastIn
|
||||||
=> DateTime.Now - LastMessageIn;
|
=> DateTime.UtcNow - LastMessageIn;
|
||||||
|
|
||||||
public static void Initialize() {
|
public static void Initialize() {
|
||||||
if(IsOpen || ListeningThread != null)
|
if(IsOpen || ListeningThread != null)
|
||||||
|
@ -52,7 +52,7 @@ namespace SockScape {
|
||||||
var endPoint = new IPEndPoint(IPAddress.Any, 0);
|
var endPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||||
while(Sock.Available > 0) {
|
while(Sock.Available > 0) {
|
||||||
var data = Sock.Receive(ref endPoint);
|
var data = Sock.Receive(ref endPoint);
|
||||||
LastMessageIn = DateTime.Now;
|
LastMessageIn = DateTime.UtcNow;
|
||||||
|
|
||||||
bool readRaw = Encryptor == null
|
bool readRaw = Encryptor == null
|
||||||
|| data.Take(Packet.MagicNumber.Length).SequenceEqual(Packet.MagicNumber);
|
|| data.Take(Packet.MagicNumber.Length).SequenceEqual(Packet.MagicNumber);
|
||||||
|
@ -108,7 +108,7 @@ namespace SockScape {
|
||||||
|
|
||||||
public static void Send(byte[] bytes) {
|
public static void Send(byte[] bytes) {
|
||||||
Sock.Send(bytes, bytes.Length);
|
Sock.Send(bytes, bytes.Length);
|
||||||
LastMessageOut = DateTime.Now;
|
LastMessageOut = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Close() {
|
public static void Close() {
|
||||||
|
|
|
@ -63,9 +63,9 @@ namespace SockScape {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(IsProspectConnected(client) && encryptor == null)
|
if(IsProspectConnected(client) && encryptor == null)
|
||||||
Prospects[client].LastReceive = DateTime.Now;
|
Prospects[client].LastReceive = DateTime.UtcNow;
|
||||||
else if(IsClientConnected(client) && encryptor != null)
|
else if(IsClientConnected(client) && encryptor != null)
|
||||||
Clients[client].LastReceive = DateTime.Now;
|
Clients[client].LastReceive = DateTime.UtcNow;
|
||||||
|
|
||||||
switch((kIntraSlaveId)packet.Id) {
|
switch((kIntraSlaveId)packet.Id) {
|
||||||
case kIntraSlaveId.InitiationAttempt:
|
case kIntraSlaveId.InitiationAttempt:
|
||||||
|
@ -75,7 +75,7 @@ namespace SockScape {
|
||||||
if(packet[0] == Configuration.General["Master Secret"]) {
|
if(packet[0] == Configuration.General["Master Secret"]) {
|
||||||
var key = new Key();
|
var key = new Key();
|
||||||
Prospects[client] = new Client {
|
Prospects[client] = new Client {
|
||||||
LastReceive = DateTime.Now,
|
LastReceive = DateTime.UtcNow,
|
||||||
Address = endPoint,
|
Address = endPoint,
|
||||||
Key = key
|
Key = key
|
||||||
};
|
};
|
||||||
|
@ -90,7 +90,7 @@ namespace SockScape {
|
||||||
|
|
||||||
var privateKey = Prospects[client].Key.ParseResponsePacket(packet);
|
var privateKey = Prospects[client].Key.ParseResponsePacket(packet);
|
||||||
if(privateKey != -1) {
|
if(privateKey != -1) {
|
||||||
Prospects[client].LastReceive = DateTime.Now;
|
Prospects[client].LastReceive = DateTime.UtcNow;
|
||||||
Prospects[client].Encryptor = new BlockCipher(privateKey);
|
Prospects[client].Encryptor = new BlockCipher(privateKey);
|
||||||
Clients[client] = Prospects[client];
|
Clients[client] = Prospects[client];
|
||||||
Prospects.Remove(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);
|
.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)
|
if(expiredClients.Count > 0)
|
||||||
MasterServerList.RemoveServersByOwners(expiredClients);
|
MasterServerList.RemoveServersByOwners(expiredClients);
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ namespace SockScape {
|
||||||
public class Client {
|
public class Client {
|
||||||
public IPEndPoint Address { get; set; }
|
public IPEndPoint Address { get; set; }
|
||||||
public DateTime LastReceive { 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 BlockCipher Encryptor { get; set; }
|
||||||
public Key Key { get; set; }
|
public Key Key { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace SockScape {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnParse() {
|
protected override void OnParse() {
|
||||||
if((DateTime.UtcNow - ConnectionOpened).Seconds > 60) {
|
if((DateTime.UtcNow - ConnectionOpened).TotalSeconds > 60) {
|
||||||
Disconnect(Frame.kClosingReason.ProtocolError, "Logon request timed out.");
|
Disconnect(Frame.kClosingReason.ProtocolError, "Logon request timed out.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue