|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using ZeroLevel;
|
|
|
|
|
using ZeroLevel.Services.HashFunctions;
|
|
|
|
|
using ZeroLevel.Services.Serialization;
|
|
|
|
|
|
|
|
|
|
namespace Server
|
|
|
|
|
{
|
|
|
|
|
public class Info
|
|
|
|
|
: IBinarySerializable
|
|
|
|
|
{
|
|
|
|
|
public uint Id;
|
|
|
|
|
public uint Length;
|
|
|
|
|
public uint Checksum;
|
|
|
|
|
|
|
|
|
|
public void Deserialize(IBinaryReader reader)
|
|
|
|
|
{
|
|
|
|
|
this.Id = reader.ReadUInt32();
|
|
|
|
|
this.Length = reader.ReadUInt32();
|
|
|
|
|
this.Checksum = reader.ReadUInt32();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Serialize(IBinaryWriter writer)
|
|
|
|
|
{
|
|
|
|
|
writer.WriteUInt32(this.Id);
|
|
|
|
|
writer.WriteUInt32(this.Length);
|
|
|
|
|
writer.WriteUInt32(this.Checksum);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class Fragment
|
|
|
|
|
: IBinarySerializable
|
|
|
|
|
{
|
|
|
|
|
public uint Id;
|
|
|
|
|
public uint Offset;
|
|
|
|
|
public uint Checksum;
|
|
|
|
|
public byte[] Payload;
|
|
|
|
|
|
|
|
|
|
public void Deserialize(IBinaryReader reader)
|
|
|
|
|
{
|
|
|
|
|
this.Id = reader.ReadUInt32();
|
|
|
|
|
this.Offset = reader.ReadUInt32();
|
|
|
|
|
this.Checksum = reader.ReadUInt32();
|
|
|
|
|
this.Payload = reader.ReadBytes();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Serialize(IBinaryWriter writer)
|
|
|
|
|
{
|
|
|
|
|
writer.WriteUInt32(this.Id);
|
|
|
|
|
writer.WriteUInt32(this.Offset);
|
|
|
|
|
writer.WriteUInt32(this.Checksum);
|
|
|
|
|
writer.WriteBytes(this.Payload);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class Data
|
|
|
|
|
{
|
|
|
|
|
public uint Checksum;
|
|
|
|
|
public uint Length;
|
|
|
|
|
public uint ActualLength;
|
|
|
|
|
public byte[] Payload;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class Program
|
|
|
|
|
{
|
|
|
|
|
private readonly static Dictionary<uint, Data> _incoming = new Dictionary<uint, Data>();
|
|
|
|
|
private readonly static XXHashUnsafe _hash = new XXHashUnsafe(667);
|
|
|
|
|
|
|
|
|
|
static void Main(string[] args)
|
|
|
|
|
{
|
|
|
|
|
Log.AddConsoleLogger(ZeroLevel.Logging.LogLevel.FullDebug | ZeroLevel.Logging.LogLevel.System);
|
|
|
|
|
var ex = Bootstrap.CreateExchange();
|
|
|
|
|
var port = ReadPort();
|
|
|
|
|
var server = ex.UseHost(port);
|
|
|
|
|
|
|
|
|
|
server.RegisterInbox<string, string>("time", (c, s) => { Log.Info($"Request time: [{s}]"); return DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss"); });
|
|
|
|
|
server.RegisterInbox<string, string>("whois", (c, s) => { Log.Info($"Request whois: [{s}]"); return $"[{Environment.MachineName}] {Environment.UserDomainName}\\{Environment.UserName}"; });
|
|
|
|
|
|
|
|
|
|
server.RegisterInbox<Info, bool>("start", (c, i) =>
|
|
|
|
|
{
|
|
|
|
|
Start(i);
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
server.RegisterInbox<Fragment, bool>("part", (c, p) =>
|
|
|
|
|
{
|
|
|
|
|
return WriteFragment(p);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
server.RegisterInbox<uint>("complete", (c, id) => Complete(id));
|
|
|
|
|
|
|
|
|
|
Log.Warning("Started");
|
|
|
|
|
|
|
|
|
|
server.OnConnect += Server_OnConnect;
|
|
|
|
|
server.OnDisconnect += Server_OnDisconnect;
|
|
|
|
|
Console.ReadKey();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void Start(Info info)
|
|
|
|
|
{
|
|
|
|
|
var data = new Data
|
|
|
|
|
{
|
|
|
|
|
Checksum = info.Checksum,
|
|
|
|
|
ActualLength = 0,
|
|
|
|
|
Length = info.Length,
|
|
|
|
|
Payload = new byte[info.Length]
|
|
|
|
|
};
|
|
|
|
|
_incoming.Add(info.Id, data);
|
|
|
|
|
Log.Info($"Start incoming data id '{info.Id}'. {info.Length} bytes. Checksum: {info.Checksum}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool WriteFragment(Fragment fragment)
|
|
|
|
|
{
|
|
|
|
|
var checksum = _hash.Hash(fragment.Payload);
|
|
|
|
|
if (checksum != fragment.Checksum)
|
|
|
|
|
{
|
|
|
|
|
Log.Warning($"[WriteFragment] Wrong checksum (checksum: {checksum} expected: {fragment.Checksum})! ID: '{fragment.Id}'. Offset: '{fragment.Offset}'. Length: '{fragment.Payload.Length}' bytes.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!_incoming.ContainsKey(fragment.Id))
|
|
|
|
|
{
|
|
|
|
|
Log.Warning($"[WriteFragment] Data ID: '{fragment.Id}' not found. Offset: '{fragment.Offset}'. Length: '{fragment.Payload.Length}' bytes.");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
Array.Copy(fragment.Payload, 0, _incoming[fragment.Id].Payload, fragment.Offset, fragment.Payload.Length);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void Complete(uint id)
|
|
|
|
|
{
|
|
|
|
|
if (_incoming.ContainsKey(id))
|
|
|
|
|
{
|
|
|
|
|
var checksum = _hash.Hash(_incoming[id].Payload);
|
|
|
|
|
if (checksum != _incoming[id].Checksum)
|
|
|
|
|
{
|
|
|
|
|
Log.Warning($"[Complete] Wrong checksum (checksum: {checksum} expected: {_incoming[id].Checksum})! ID: '{id}'");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Log.Info($"Data '{id}' successfully received");
|
|
|
|
|
}
|
|
|
|
|
_incoming.Remove(id);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Log.Warning($"[Complete] Data ID '{id}' not found");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void Server_OnDisconnect(ZeroLevel.Network.ISocketClient obj)
|
|
|
|
|
{
|
|
|
|
|
Log.Info($"Client disconnected: {obj.Endpoint.Address}:{obj.Endpoint.Port}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void Server_OnConnect(ZeroLevel.Network.IClient obj)
|
|
|
|
|
{
|
|
|
|
|
Log.Info($"Client connected: {obj.Endpoint.Address}:{obj.Endpoint.Port}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int ReadPort()
|
|
|
|
|
{
|
|
|
|
|
int port = -1;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("PORT>");
|
|
|
|
|
var port_line = Console.ReadLine();
|
|
|
|
|
if (int.TryParse(port_line, out port) == false || port <= 0)
|
|
|
|
|
{
|
|
|
|
|
port = -1;
|
|
|
|
|
Console.WriteLine($"Incorrect port '{port_line}'");
|
|
|
|
|
}
|
|
|
|
|
} while (port <= 0);
|
|
|
|
|
return port;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|