From a63a9b551146c0e18fb893fe117093eff375198f Mon Sep 17 00:00:00 2001 From: ahmed Date: Wed, 15 Oct 2025 17:34:18 +0300 Subject: [PATCH] Encoding --- Esiur/Data/Codec.cs | 90 ++--- Esiur/Data/DataDeserializer.cs | 62 +-- Esiur/Data/DataSerializer.cs | 360 +++++++++++++++--- Esiur/Data/ParsedTDU.cs | 48 ++- Esiur/Data/TDUClass.cs | 3 +- Esiur/Data/TDUIdentifier.cs | 1 + Esiur/Net/IIP/DistributedConnection.cs | 11 +- .../Net/IIP/DistributedConnectionProtocol.cs | 18 +- Esiur/Net/NetworkServer.cs | 2 +- Esiur/Net/Packets/IIPAuthPacket.cs | 32 +- Esiur/Net/Packets/IIPPacket.cs | 22 +- 11 files changed, 477 insertions(+), 172 deletions(-) diff --git a/Esiur/Data/Codec.cs b/Esiur/Data/Codec.cs index c225f01..fec47bf 100644 --- a/Esiur/Data/Codec.cs +++ b/Esiur/Data/Codec.cs @@ -189,42 +189,53 @@ public static class Codec /// DistributedConnection is required in case a structure in the array holds items at the other end. /// DataType, in case the data is not prepended with DataType /// Value - public static (uint, object) ParseAsync(byte[] data, uint offset, DistributedConnection connection, uint[] requestSequence, ParsedTDU? dataType = null) + public static (uint, object) ParseAsync(byte[] data, uint offset, DistributedConnection connection, uint[] requestSequence) { - uint len = 0; - if (dataType == null) + var tdu = ParsedTDU.Parse(data, offset, (uint)data.Length); + + if (tdu.Class == TDUClass.Invalid) + throw new NullReferenceException("DataType can't be parsed."); + + if (tdu.Class == TDUClass.Fixed) { - (var longLen, dataType) = ParsedTDU.Parse(data, offset, (uint)data.Length); - - if (dataType == null) - throw new NullReferenceException("DataType can't be parsed."); - - len = (uint)longLen; - offset = dataType.Value.Offset; + return ((uint)tdu.TotalLength, FixedAsyncParsers[tdu.Exponent][tdu.Index](tdu, connection, requestSequence)); } - else - len = (uint)dataType.Value.ContentLength; - - var tt = dataType.Value; - - //Console.WriteLine("Parsing " + tt.Class + " " + tt.Identifier); - - if (tt.Class == TDUClass.Fixed) + else if (tdu.Class == TDUClass.Dynamic) { - return (len, FixedAsyncParsers[tt.Exponent][tt.Index](tt, connection, requestSequence)); + return ((uint)tdu.TotalLength, DynamicAsyncParsers[tdu.Index](tdu, connection, requestSequence)); } - else if (tt.Class == TDUClass.Dynamic) + else if (tdu.Class == TDUClass.Typed) { - return (len, DynamicAsyncParsers[tt.Index](tt, connection, requestSequence)); + return ((uint)tdu.TotalLength, TypedAsyncParsers[tdu.Index](tdu, connection, requestSequence)); } - else if (tt.Class == TDUClass.Typed) + else // if (tt.Class == TDUClass.Extension) { - return (len, TypedAsyncParsers[tt.Index](tt, connection, requestSequence)); + return ((uint)tdu.TotalLength, ExtendedAsyncParsers[tdu.Index](tdu, connection, requestSequence)); + } - else if (tt.Class == TDUClass.Extension) + } + + public static (uint, object) ParseAsync(ParsedTDU tdu, DistributedConnection connection, uint[] requestSequence) + { + if (tdu.Class == TDUClass.Invalid) + throw new NullReferenceException("DataType can't be parsed."); + + if (tdu.Class == TDUClass.Fixed) { - return (len, ExtendedAsyncParsers[tt.Index](tt, connection, requestSequence)); + return ((uint)tdu.TotalLength, FixedAsyncParsers[tdu.Exponent][tdu.Index](tdu, connection, requestSequence)); + } + else if (tdu.Class == TDUClass.Dynamic) + { + return ((uint)tdu.TotalLength, DynamicAsyncParsers[tdu.Index](tdu, connection, requestSequence)); + } + else if (tdu.Class == TDUClass.Typed) + { + return ((uint)tdu.TotalLength, TypedAsyncParsers[tdu.Index](tdu, connection, requestSequence)); + } + else // if (tt.Class == TDUClass.Extension) + { + return ((uint)tdu.TotalLength, ExtendedAsyncParsers[tdu.Index](tdu, connection, requestSequence)); } } @@ -252,34 +263,27 @@ public static class Codec public static (uint, object) ParseSync(byte[] data, uint offset, Warehouse warehouse) { - uint len = 0; + var tdu = ParsedTDU.Parse(data, offset, (uint)data.Length); - - var (longLen, dataType) = ParsedTDU.Parse(data, offset, (uint)data.Length); - - if (dataType == null) + if (tdu.Class == TDUClass.Invalid) throw new NullReferenceException("DataType can't be parsed."); - len = (uint)longLen; - offset = dataType.Value.Offset; - var tt = dataType.Value; - - if (tt.Class == TDUClass.Fixed) + if (tdu.Class == TDUClass.Fixed) { - return (len, FixedParsers[tt.Exponent][tt.Index](tt, warehouse)); + return ((uint)tdu.TotalLength, FixedParsers[tdu.Exponent][tdu.Index](tdu, warehouse)); } - else if (tt.Class == TDUClass.Dynamic) + else if (tdu.Class == TDUClass.Dynamic) { - return (len, DynamicParsers[tt.Index](tt, warehouse)); + return ((uint)tdu.TotalLength, DynamicParsers[tdu.Index](tdu, warehouse)); } - else if (tt.Class == TDUClass.Typed) + else if (tdu.Class == TDUClass.Typed) { - return (len, TypedParsers[tt.Index](tt, warehouse)); + return ((uint)tdu.TotalLength, TypedParsers[tdu.Index](tdu, warehouse)); } else { - return (len, ExtendedParsers[tt.Index](tt, warehouse)); + return ((uint)tdu.TotalLength, ExtendedParsers[tdu.Index](tdu, warehouse)); } } /// @@ -326,8 +330,8 @@ public static class Codec [typeof(float?)] = DataSerializer.Float32Composer, [typeof(long)] = DataSerializer.Int64Composer, [typeof(long?)] = DataSerializer.Int64Composer, - [typeof(ulong)] = DataSerializer.UIn64Composer, - [typeof(ulong?)] = DataSerializer.UIn64Composer, + [typeof(ulong)] = DataSerializer.UInt64Composer, + [typeof(ulong?)] = DataSerializer.UInt64Composer, [typeof(double)] = DataSerializer.Float64Composer, [typeof(double?)] = DataSerializer.Float64Composer, [typeof(DateTime)] = DataSerializer.DateTimeComposer, diff --git a/Esiur/Data/DataDeserializer.cs b/Esiur/Data/DataDeserializer.cs index 5c240d7..f0a7b5c 100644 --- a/Esiur/Data/DataDeserializer.cs +++ b/Esiur/Data/DataDeserializer.cs @@ -450,7 +450,7 @@ public static class DataDeserializer { var classId = tdu.Metadata.GetUUID(0); - + var template = warehouse.GetTemplateByClassId(classId, TemplateType.Record); @@ -535,7 +535,7 @@ public static class DataDeserializer { var classId = tdu.Metadata.GetUUID(0); - + var index = tdu.Data[tdu.Offset]; var template = warehouse.GetTemplateByClassId(classId, TemplateType.Enum); @@ -794,7 +794,7 @@ public static class DataDeserializer var (keyCs, keyRepType) = RepresentationType.Parse(tdu.Metadata, 0); var (valueCs, valueRepType) = RepresentationType.Parse(tdu.Metadata, keyCs); - + var map = (IMap)Activator.CreateInstance(typeof(Map<,>).MakeGenericType(keyRepType.GetRuntimeType(warehouse), valueRepType.GetRuntimeType(warehouse))); @@ -828,8 +828,9 @@ public static class DataDeserializer public static AsyncReply TupleParserAsync(ParsedTDU tdu, DistributedConnection connection, uint[] requestSequence) { + var rt = new AsyncReply(); - var results = new List(); + var results = new AsyncBag(); var tupleSize = tdu.Metadata[0]; var types = new List(); @@ -919,7 +920,7 @@ public static class DataDeserializer var length = tdu.ContentLength; var offset = tdu.Offset; - + while (length > 0) { var (cs, reply) = Codec.ParseSync(tdu.Data, offset, warehouse); @@ -977,20 +978,37 @@ public static class DataDeserializer var rt = new AsyncBag(); // get the type - var (hdrCs, rep) = RepresentationType.Parse(data, offset); + var (hdrCs, rep) = RepresentationType.Parse(tdu.Metadata, 0); - offset += hdrCs; - length -= hdrCs; var runtimeType = rep.GetRuntimeType(connection.Instance.Warehouse); rt.ArrayType = runtimeType; + ParsedTDU current; + ParsedTDU? previous = null; + + var offset = tdu.Offset; + var length = tdu.ContentLength; + var ends = offset + (uint)length; + while (length > 0) { - var (cs, reply) = Codec.ParseAsync(data, offset, connection, requestSequence); - + current = ParsedTDU.Parse(tdu.Data, offset, ends); + + if (current.Class == TDUClass.Invalid) + throw new Exception("Unknown type."); + + + if (current.Identifier == TDUIdentifier.TypeContinuation) + { + current.Class = previous.Value.Class; + current.Identifier = previous.Value.Identifier; + current.Metadata = previous.Value.Metadata; + } + + var (cs, reply) = Codec.ParseAsync(tdu.Data, offset, connection, requestSequence); rt.Add(reply); @@ -1021,7 +1039,7 @@ public static class DataDeserializer var list = new List(); - ParsedTDU? current; + ParsedTDU current; ParsedTDU? previous = null; var offset = tdu.Offset; @@ -1030,21 +1048,20 @@ public static class DataDeserializer while (length > 0) { - (var longLen, current) = ParsedTDU.Parse(tdu.Data, offset, ends); + current = ParsedTDU.Parse(tdu.Data, offset, ends); - if (current == null) + if (current.Class == TDUClass.Invalid) throw new Exception("Unknown type."); - var cur = (ParsedTDU)current.Value; - if (cur.Identifier == TDUIdentifier.TypeContinuation) + if (current.Identifier == TDUIdentifier.TypeContinuation) { - cur.Class = previous.Value.Class; - cur.Identifier = previous.Value.Identifier; - cur.Metadata = previous.Value.Metadata; + current.Class = previous.Value.Class; + current.Identifier = previous.Value.Identifier; + current.Metadata = previous.Value.Metadata; } - var (cs, reply) = Codec.ParseSync(cur, warehouse); + var (cs, reply) = Codec.ParseSync(current, warehouse); list.Add(reply); @@ -1052,7 +1069,7 @@ public static class DataDeserializer { offset += (uint)cs; length -= (uint)cs; - previous = cur; + previous = current; } else throw new Exception("Error while parsing structured data"); @@ -1061,7 +1078,7 @@ public static class DataDeserializer var rt = Array.CreateInstance(runtimeType, list.Count); Array.Copy(list.ToArray(), rt, rt.Length); - + return rt; } @@ -1070,7 +1087,8 @@ public static class DataDeserializer var rt = new AsyncBag(); - ListParserAsync(data, offset, length, connection, requestSequence).Then(x => + ListParserAsync(new ParsedTDU() { Data = data, Offset = offset, ContentLength = length } + , connection, requestSequence).Then(x => { var ar = (object[])x; var pvs = new List(); diff --git a/Esiur/Data/DataSerializer.cs b/Esiur/Data/DataSerializer.cs index 77cdfd2..60bb72b 100644 --- a/Esiur/Data/DataSerializer.cs +++ b/Esiur/Data/DataSerializer.cs @@ -3,6 +3,7 @@ using Esiur.Net.IIP; using Esiur.Resource; using Esiur.Resource.Template; using System; +using System.Buffers.Binary; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -17,77 +18,271 @@ public static class DataSerializer public static unsafe TDU Int32Composer(object value, Warehouse warehouse, DistributedConnection connection) { var v = (int)value; - var rt = new byte[4]; - fixed (byte* ptr = rt) - *((int*)ptr) = v; - return new TDU(TDUIdentifier.Int32, rt, 4); + + if (v >= sbyte.MinValue && v <= sbyte.MaxValue) + { + return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1); + } + else if (v >= short.MinValue && v <= short.MaxValue) + { + // Fits in 2 bytes + var rt = new byte[2]; + fixed (byte* ptr = rt) + *((short*)ptr) = (short)v; + + return new TDU(TDUIdentifier.Int16, rt, 2); + } + else + { + // Use full 4 bytes + var rt = new byte[4]; + fixed (byte* ptr = rt) + *((int*)ptr) = v; + return new TDU(TDUIdentifier.Int32, rt, 4); + } } public static unsafe TDU UInt32Composer(object value, Warehouse warehouse, DistributedConnection connection) { var v = (uint)value; - var rt = new byte[4]; - fixed (byte* ptr = rt) - *((uint*)ptr) = v; - return new TDU(TDUIdentifier.UInt32, rt, 4); + if (v <= byte.MaxValue) + { + // Fits in 1 byte + return new TDU(TDUIdentifier.UInt8, new byte[] { (byte)v }, 1); + } + else if (v <= ushort.MaxValue) + { + // Fits in 2 bytes + var rt = new byte[2]; + fixed (byte* ptr = rt) + *((ushort*)ptr) = (ushort)v; + return new TDU(TDUIdentifier.UInt16, rt, 2); + } + else + { + // Use full 4 bytes + var rt = new byte[4]; + fixed (byte* ptr = rt) + *((uint*)ptr) = v; + + return new TDU(TDUIdentifier.UInt32, rt, 4); + } } public static unsafe TDU Int16Composer(object value, Warehouse warehouse, DistributedConnection connection) { var v = (short)value; - var rt = new byte[2]; - fixed (byte* ptr = rt) - *((short*)ptr) = v; - return new TDU(TDUIdentifier.Int16, rt, 2); + if (v >= sbyte.MinValue && v <= sbyte.MaxValue) + { + // Fits in 1 byte + return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1); + } + else + { + // Use full 2 bytes + var rt = new byte[2]; + fixed (byte* ptr = rt) + *((short*)ptr) = v; + + return new TDU(TDUIdentifier.Int16, rt, 2); + } } public static unsafe TDU UInt16Composer(object value, Warehouse warehouse, DistributedConnection connection) { var v = (ushort)value; - var rt = new byte[2]; - fixed (byte* ptr = rt) - *((ushort*)ptr) = v; - return new TDU(TDUIdentifier.UInt16, rt, 2); + if (v <= byte.MaxValue) + { + // Fits in 1 byte + return new TDU(TDUIdentifier.UInt8, new byte[] { (byte)v }, 1); + } + else + { + // Use full 2 bytes + var rt = new byte[2]; + fixed (byte* ptr = rt) + *((ushort*)ptr) = v; + + return new TDU(TDUIdentifier.UInt16, rt, 2); + } } - public static unsafe TDU Float32Composer(object value, Warehouse warehouse, DistributedConnection connection) + + public static unsafe TDU Float32Composer(object value, Warehouse warehouse, DistributedConnection connection) { - var v = (float)value; - var rt = new byte[4]; - fixed (byte* ptr = rt) - *((float*)ptr) = v; - return new TDU(TDUIdentifier.Float32, rt, 4); + float v = (float)value; + + // Special IEEE-754 values + if (float.IsNaN(v) || float.IsInfinity(v)) + { + return new TDU(TDUIdentifier.Infinity, new byte[0], 0); + } + + // If v is an exact integer, prefer smallest signed width up to Int32 + if (v == Math.Truncate(v)) + { + // Note: casts are safe because we check bounds first. + if (v >= sbyte.MinValue && v <= sbyte.MaxValue) + { + return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1); + } + + if (v >= short.MinValue && v <= short.MaxValue) + { + var rt = new byte[2]; + fixed (byte* ptr = rt) + *((short*)ptr) = (short)v; + return new TDU(TDUIdentifier.Int16, rt, 2); + } + } + + // Default: Float32 + { + var rt = new byte[4]; + fixed (byte* ptr = rt) + *((float*)ptr) = v; + return new TDU(TDUIdentifier.Float32, rt, 4); + } } - public static unsafe TDU Float64Composer(object value, Warehouse warehouse, DistributedConnection connection) + + public unsafe static TDU Float64Composer(object value, Warehouse warehouse, DistributedConnection connection) { - var v = (double)value; - var rt = new byte[8]; - fixed (byte* ptr = rt) - *((double*)ptr) = v; - return new TDU(TDUIdentifier.Float64, rt, 8); - } + double v = (double)value; + // Special IEEE-754 values + if (double.IsNaN(v) || double.IsInfinity(v)) + { + return new TDU(TDUIdentifier.Infinity, new byte[0], 0); + } + + // If v is an exact integer, choose the smallest signed width + if (v == Math.Truncate(v)) + { + if (v >= sbyte.MinValue && v <= sbyte.MaxValue) + return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1); + + if (v >= short.MinValue && v <= short.MaxValue) + { + var rt = new byte[2]; + + fixed (byte* ptr = rt) + *((short*)ptr) = (short)v; + + return new TDU(TDUIdentifier.Int16, rt, 2); + } + + if (v >= int.MinValue && v <= int.MaxValue) + { + var rt = new byte[4]; + + fixed (byte* ptr = rt) + *((int*)ptr) = (int)v; + + return new TDU(TDUIdentifier.Int32, rt, 4); + } + + // If it's integral but outside Int64 range, fall through to Float64. + } + + // Try exact Float32 (decimal subset of doubles) + var f = (float)v; + if ((double)f == v) + { + var rt = new byte[4]; + + fixed (byte* ptr = rt) + *((float*)ptr) = (byte)v; + + return new TDU(TDUIdentifier.Float32, rt, 4); + } + + // Default: Float64 + { + var rt = new byte[8]; + fixed (byte* ptr = rt) + *((double*)ptr) = v; + return new TDU(TDUIdentifier.Float64, rt, 8); + } + } public static unsafe TDU Int64Composer(object value, Warehouse warehouse, DistributedConnection connection) { var v = (long)value; - var rt = new byte[8]; - fixed (byte* ptr = rt) - *((long*)ptr) = v; - return new TDU(TDUIdentifier.Int64, rt, 8); + + if (v >= sbyte.MinValue && v <= sbyte.MaxValue) + { + // Fits in 1 byte + return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1); + } + else if (v >= short.MinValue && v <= short.MaxValue) + { + // Fits in 2 bytes + var rt = new byte[2]; + fixed (byte* ptr = rt) + *((short*)ptr) = (short)v; + + return new TDU(TDUIdentifier.Int16, rt, 2); + } + else if (v >= int.MinValue && v <= int.MaxValue) + { + // Fits in 4 bytes + var rt = new byte[4]; + fixed (byte* ptr = rt) + *((int*)ptr) = (int)v; + + return new TDU(TDUIdentifier.Int32, rt, 4); + } + else + { + // Use full 8 bytes + var rt = new byte[8]; + fixed (byte* ptr = rt) + *((long*)ptr) = v; + + return new TDU(TDUIdentifier.Int64, rt, 8); + } } - public static unsafe TDU UIn64Composer(object value, Warehouse warehouse, DistributedConnection connection) + public static unsafe TDU UInt64Composer(object value, Warehouse warehouse, DistributedConnection connection) { var v = (ulong)value; - var rt = new byte[8]; - fixed (byte* ptr = rt) - *((ulong*)ptr) = v; - return new TDU(TDUIdentifier.UInt64, rt, 8); + + if (v <= byte.MaxValue) + { + // Fits in 1 byte + return new TDU(TDUIdentifier.UInt8, new byte[] { (byte)v }, 1); + } + else if (v <= ushort.MaxValue) + { + // Fits in 2 bytes + var rt = new byte[2]; + fixed (byte* ptr = rt) + *((ushort*)ptr) = (ushort)v; + + return new TDU(TDUIdentifier.UInt16, rt, 2); + } + else if (v <= uint.MaxValue) + { + // Fits in 4 bytes + var rt = new byte[4]; + fixed (byte* ptr = rt) + *((uint*)ptr) = (uint)v; + + return new TDU(TDUIdentifier.UInt32, rt, 4); + } + else + { + // Use full 8 bytes + var rt = new byte[8]; + fixed (byte* ptr = rt) + *((ulong*)ptr) = v; + + return new TDU(TDUIdentifier.UInt64, rt, 8); + } } @@ -101,18 +296,89 @@ public static class DataSerializer return new TDU(TDUIdentifier.DateTime, rt, 8); } + //public static unsafe TDU Decimal128Composer(object value, Warehouse warehouse, DistributedConnection connection) + //{ + // var v = (decimal)value; + // var rt = new byte[16]; + // fixed (byte* ptr = rt) + // *((decimal*)ptr) = v; + + // return new TDU(TDUIdentifier.Decimal128, rt, 16); + //} + public static unsafe TDU Decimal128Composer(object value, Warehouse warehouse, DistributedConnection connection) { var v = (decimal)value; - var rt = new byte[16]; - fixed (byte* ptr = rt) - *((decimal*)ptr) = v; - return new TDU(TDUIdentifier.Decimal128, rt, 16); + // Prefer smallest exact signed integer if no fractional part + int[] bits = decimal.GetBits(v); + int flags = bits[3]; + int scale = (flags >> 16) & 0x7F; + + if (scale == 0) + { + if (v >= sbyte.MinValue && v <= sbyte.MaxValue) + return new TDU(TDUIdentifier.Int8, new byte[] { (byte)(sbyte)v }, 1); + + if (v >= short.MinValue && v <= short.MaxValue) + { + var b = new byte[2]; + BinaryPrimitives.WriteInt16LittleEndian(b, (short)v); + return new TDU(TDUIdentifier.Int16, b, 2); + } + + if (v >= int.MinValue && v <= int.MaxValue) + { + var b = new byte[4]; + BinaryPrimitives.WriteInt32LittleEndian(b, (int)v); + return new TDU(TDUIdentifier.Int32, b, 4); + } + + if (v >= long.MinValue && v <= long.MaxValue) + { + var b = new byte[8]; + BinaryPrimitives.WriteInt64LittleEndian(b, (long)v); + return new TDU(TDUIdentifier.Int64, b, 8); + } + // else fall through (needs 96+ bits) + } + + // Try exact Float32 (4 bytes) + // Exactness test: decimal -> float -> decimal must equal original + float f = (float)v; + if ((decimal)f == v) + { + var rt = new byte[4]; + + fixed (byte* ptr = rt) + *((float*)ptr) = f; + + return new TDU(TDUIdentifier.Float32, rt, 4); + } + + // Try exact Float64 (8 bytes) + double d = (double)v; + if ((decimal)d == v) + { + var rt = new byte[4]; + + fixed (byte* ptr = rt) + *((double*)ptr) = d; + + return new TDU(TDUIdentifier.Float64, rt, 8); + } + + { + // Fallback: full .NET decimal (16 bytes): lo, mid, hi, flags (scale/sign) + var rt = new byte[16]; + + fixed (byte* ptr = rt) + *((decimal*)ptr) = v; + + return new TDU(TDUIdentifier.Decimal128, rt, 16); + } } - - public static TDU StringComposer(object value, Warehouse warehouse, DistributedConnection connection) { var b = Encoding.UTF8.GetBytes((string)value); @@ -228,8 +494,6 @@ public static class DataSerializer { var composed = ArrayComposer((IEnumerable)value, warehouse, connection); - Console.WriteLine(composed.ToHex()); - if (composed == null) return new TDU(TDUIdentifier.Null, new byte[0], 0); @@ -331,12 +595,12 @@ public static class DataSerializer foreach (var i in value) { var tdu = Codec.ComposeInternal(i, warehouse, connection); - if (previous != null && tdu.MatchType(previous.Value)) + if (previous != null && tdu.MatchType(previous.Value)) { var d = tdu.Composed.Clip(tdu.ContentOffset, (uint)tdu.Composed.Length - tdu.ContentOffset); - var ntd = new TDU(TDUIdentifier.TypeContinuation, d,(ulong) d.Length); + var ntd = new TDU(TDUIdentifier.TypeContinuation, d, (ulong)d.Length); rt.AddRange(ntd.Composed); } else diff --git a/Esiur/Data/ParsedTDU.cs b/Esiur/Data/ParsedTDU.cs index 9f564d6..cc17a1f 100644 --- a/Esiur/Data/ParsedTDU.cs +++ b/Esiur/Data/ParsedTDU.cs @@ -16,7 +16,7 @@ namespace Esiur.Data public ulong TotalLength; public byte[] Metadata; - public static (ulong, ParsedTDU?) Parse(byte[] data, uint offset, uint ends) + public static ParsedTDU Parse(byte[] data, uint offset, uint ends) { var h = data[offset++]; @@ -27,7 +27,7 @@ namespace Esiur.Data var exp = (h & 0x38) >> 3; if (exp == 0) - return (1, new ParsedTDU() + return new ParsedTDU() { Identifier = (TDUIdentifier)h, Data = data, @@ -37,16 +37,20 @@ namespace Esiur.Data Index = (byte)h & 0x7, ContentLength = 0, TotalLength = 1, - }); + }; ulong cl = (ulong)(1 << (exp - 1)); if (ends - offset < cl) - return (cl - (ends - offset), null); + return new ParsedTDU() + { + Class = TDUClass.Invalid, + TotalLength = (cl - (ends - offset)) + }; //offset += (uint)cl; - return (1 + cl, new ParsedTDU() + return new ParsedTDU() { Identifier = (TDUIdentifier)h, Data = data, @@ -56,14 +60,18 @@ namespace Esiur.Data TotalLength = 1 + cl, Exponent = (byte)exp, Index = (byte)h & 0x7, - }); + }; } else if (cls == TDUClass.Typed) { ulong cll = (ulong)(h >> 3) & 0x7; if (ends - offset < cll) - return (cll - (ends - offset), null); + return new ParsedTDU() + { + Class = TDUClass.Invalid, + TotalLength = (cll - (ends - offset)) + }; ulong cl = 0; @@ -71,13 +79,17 @@ namespace Esiur.Data cl = cl << 8 | data[offset++]; if (ends - offset < cl) - return (cl - (ends - offset), null); + return new ParsedTDU() + { + TotalLength = (cl - (ends - offset)), + Class = TDUClass.Invalid, + }; var metaData = DC.Clip(data, offset + 1, data[offset]); offset += data[offset] + (uint)1; - return (1 + cl + cll, new ParsedTDU() + return new ParsedTDU() { Identifier = (TDUIdentifier)(h & 0xC7), Data = data, @@ -87,14 +99,18 @@ namespace Esiur.Data TotalLength = 1 + cl + cll, Index = (byte)h & 0x7, Metadata = metaData, - }); + }; } else { ulong cll = (ulong)(h >> 3) & 0x7; if (ends - offset < cll) - return (cll - (ends - offset), null); + return new ParsedTDU() + { + Class = TDUClass.Invalid, + TotalLength = (cll - (ends - offset)) + }; ulong cl = 0; @@ -102,10 +118,14 @@ namespace Esiur.Data cl = cl << 8 | data[offset++]; if (ends - offset < cl) - return (cl - (ends - offset), null); + return new ParsedTDU() + { + Class = TDUClass.Invalid, + TotalLength = (cl - (ends - offset)) + }; - return (1 + cl + cll, + return new ParsedTDU() { Identifier = (TDUIdentifier)(h & 0xC7), @@ -115,7 +135,7 @@ namespace Esiur.Data ContentLength = cl, TotalLength = 1 + cl + cll, Index = (byte)h & 0x7 - }); + }; } } diff --git a/Esiur/Data/TDUClass.cs b/Esiur/Data/TDUClass.cs index 31a965c..2922031 100644 --- a/Esiur/Data/TDUClass.cs +++ b/Esiur/Data/TDUClass.cs @@ -9,6 +9,7 @@ namespace Esiur.Data Fixed = 0x0, Dynamic = 0x1, Typed = 0x2, - Extension = 0x3 + Extension = 0x3, + Invalid } } diff --git a/Esiur/Data/TDUIdentifier.cs b/Esiur/Data/TDUIdentifier.cs index 881a538..d999735 100644 --- a/Esiur/Data/TDUIdentifier.cs +++ b/Esiur/Data/TDUIdentifier.cs @@ -10,6 +10,7 @@ namespace Esiur.Data False = 0x1, True = 0x2, NotModified = 0x3, + Infinity = 0x4, UInt8 = 0x8, Int8 = 0x9, Char8 = 0xA, diff --git a/Esiur/Net/IIP/DistributedConnection.cs b/Esiur/Net/IIP/DistributedConnection.cs index d4960b5..b26a0ef 100644 --- a/Esiur/Net/IIP/DistributedConnection.cs +++ b/Esiur/Net/IIP/DistributedConnection.cs @@ -438,7 +438,7 @@ public partial class DistributedConnection : NetworkConnection, IStore { // Invoke case IIPPacketNotification.PropertyModified: - IIPNotificationPropertyModified(dt, msg); + IIPNotificationPropertyModified(dt); break; case IIPPacketNotification.EventOccurred: IIPNotificationEventOccurred(dt, msg); @@ -448,7 +448,7 @@ public partial class DistributedConnection : NetworkConnection, IStore IIPNotificationResourceDestroyed(dt, msg); break; case IIPPacketNotification.ResourceReassigned: - IIPNotificationResourceReassigned(dt, msg); + IIPNotificationResourceReassigned(dt); break; case IIPPacketNotification.ResourceMoved: IIPNotificationResourceMoved(dt, msg); @@ -537,7 +537,7 @@ public partial class DistributedConnection : NetworkConnection, IStore switch (packet.Reply) { case IIPPacketReply.Completed: - IIPReplyCompleted(packet.CallbackId, dt, msg); + IIPReplyCompleted(packet.CallbackId, dt); break; case IIPPacketReply.Propagated: IIPReplyPropagated(packet.CallbackId, dt, msg); @@ -554,7 +554,7 @@ public partial class DistributedConnection : NetworkConnection, IStore break; case IIPPacketReply.Chunk: - IIPReplyChunk(packet.CallbackId, dt, msg); + IIPReplyChunk(packet.CallbackId, dt); break; case IIPPacketReply.Warning: @@ -1344,7 +1344,6 @@ public partial class DistributedConnection : NetworkConnection, IStore protected override void DataReceived(NetworkBuffer data) { - //Console.WriteLine("DR " + data.Available + " " + RemoteEndPoint.ToString()); var msg = data.Read(); uint offset = 0; uint ends = (uint)msg.Length; @@ -1353,8 +1352,6 @@ public partial class DistributedConnection : NetworkConnection, IStore var chunkId = (new Random()).Next(1000, 1000000); - //var list = new List>();// double, IIPPacketCommand>(); - this.Socket.Hold(); diff --git a/Esiur/Net/IIP/DistributedConnectionProtocol.cs b/Esiur/Net/IIP/DistributedConnectionProtocol.cs index 65f39cd..b7f35d7 100644 --- a/Esiur/Net/IIP/DistributedConnectionProtocol.cs +++ b/Esiur/Net/IIP/DistributedConnectionProtocol.cs @@ -262,7 +262,7 @@ partial class DistributedConnection SendReply(IIPPacketReply.Chunk, callbackId, chunk); } - void IIPReplyCompleted(uint callbackId, ParsedTDU dataType, byte[] data) + void IIPReplyCompleted(uint callbackId, ParsedTDU dataType) { var req = requests.Take(callbackId); @@ -272,7 +272,7 @@ partial class DistributedConnection return; } - var (_, parsed) = Codec.ParseAsync(data, 0, this, null, dataType); + var (_, parsed) = Codec.ParseAsync(dataType, this, null); if (parsed is AsyncReply reply) { reply.Then(result => @@ -374,14 +374,14 @@ partial class DistributedConnection - void IIPReplyChunk(uint callbackId, ParsedTDU dataType, byte[] data) + void IIPReplyChunk(uint callbackId, ParsedTDU dataType) { var req = requests[callbackId]; if (req == null) return; - var (_, parsed) = Codec.ParseAsync(data, dataType.Offset, this, null, dataType); + var (_, parsed) = Codec.ParseAsync(dataType, this, null); if (parsed is AsyncReply reply) reply.Then(result => req.TriggerChunk(result)); @@ -389,7 +389,7 @@ partial class DistributedConnection req.TriggerChunk(parsed); } - void IIPNotificationResourceReassigned(ParsedTDU dataType, byte[] data) + void IIPNotificationResourceReassigned(ParsedTDU dataType) { // uint resourceId, uint newResourceId } @@ -429,11 +429,11 @@ partial class DistributedConnection } - void IIPNotificationPropertyModified(ParsedTDU dataType, byte[] data) + void IIPNotificationPropertyModified(ParsedTDU dataType) { // resourceId, index, value var (valueOffset, valueSize, args) = - DataDeserializer.LimitedCountListParser(data, dataType.Offset, dataType.ContentLength, Instance.Warehouse, 2); + DataDeserializer.LimitedCountListParser(dataType.Data, dataType.Offset, dataType.ContentLength, Instance.Warehouse, 2); var rid = (uint)args[0]; var index = (byte)args[1]; @@ -447,7 +447,7 @@ partial class DistributedConnection var item = new AsyncReply(); queue.Add(item); - var (_, parsed) = Codec.ParseAsync(data, valueOffset, this, null); + var (_, parsed) = Codec.ParseAsync(dataType.Data, valueOffset, this, null); if (parsed is AsyncReply) { @@ -663,7 +663,7 @@ partial class DistributedConnection void IIPRequestCreateResource(uint callback, ParsedTDU dataType, byte[] data) { - var (_, parsed) = Codec.ParseAsync(data, 0, this, null, dataType); + var (_, parsed) = Codec.ParseAsync(dataType, this, null); var args = (object[])parsed; diff --git a/Esiur/Net/NetworkServer.cs b/Esiur/Net/NetworkServer.cs index f873066..0f763a0 100644 --- a/Esiur/Net/NetworkServer.cs +++ b/Esiur/Net/NetworkServer.cs @@ -117,7 +117,7 @@ public abstract class NetworkServer : IDestructible where TConnecti if (s == null) { - Console.Write("sock == null"); + Global.Log("NetworkServer", LogType.Error, "sock == null"); return; } diff --git a/Esiur/Net/Packets/IIPAuthPacket.cs b/Esiur/Net/Packets/IIPAuthPacket.cs index 0c9a6ea..506f1c8 100644 --- a/Esiur/Net/Packets/IIPAuthPacket.cs +++ b/Esiur/Net/Packets/IIPAuthPacket.cs @@ -188,13 +188,13 @@ public class IIPAuthPacket : Packet if (NotEnough(offset, ends, 1)) return -dataLengthNeeded; - (var size, DataType) = ParsedTDU.Parse(data, offset, ends); + DataType = ParsedTDU.Parse(data, offset, ends); - if (DataType == null) - return -(int)size; + if (DataType.Value.Class == TDUClass.Invalid) + return -(int)DataType.Value.TotalLength; - offset += (uint)size; + offset += (uint)DataType.Value.TotalLength; } else if (Command == IIPAuthPacketCommand.Acknowledge) @@ -208,13 +208,13 @@ public class IIPAuthPacket : Packet if (NotEnough(offset, ends, 1)) return -dataLengthNeeded; - (var size, DataType) = ParsedTDU.Parse(data, offset, ends); + DataType = ParsedTDU.Parse(data, offset, ends); - if (DataType == null) - return -(int)size; + if (DataType.Value.Class == TDUClass.Invalid) + return -(int)DataType.Value.TotalLength; - offset += (uint)size; + offset += (uint)DataType.Value.TotalLength; } else if (Command == IIPAuthPacketCommand.Action) { @@ -280,12 +280,12 @@ public class IIPAuthPacket : Packet Reference = data.GetUInt32(offset, Endian.Little); offset += 4; - (var size, DataType) = ParsedTDU.Parse(data, offset, ends); + DataType = ParsedTDU.Parse(data, offset, ends); - if (DataType == null) - return -(int)size; + if (DataType.Value.Class == TDUClass.Invalid) + return -(int)DataType.Value.TotalLength; - offset += (uint)size; + offset += (uint)DataType.Value.TotalLength; } else if (Action == IIPAuthPacketAction.IAuthHashed) @@ -445,12 +445,12 @@ public class IIPAuthPacket : Packet if (NotEnough(offset, ends, 1)) return -dataLengthNeeded; - (var size, DataType) = ParsedTDU.Parse(data, offset, ends); + DataType = ParsedTDU.Parse(data, offset, ends); - if (DataType == null) - return -(int)size; + if (DataType.Value.Class == TDUClass.Invalid) + return -(int)DataType.Value.TotalLength; - offset += (uint)size; + offset += (uint)DataType.Value.TotalLength; } } diff --git a/Esiur/Net/Packets/IIPPacket.cs b/Esiur/Net/Packets/IIPPacket.cs index f9c9860..80c8381 100644 --- a/Esiur/Net/Packets/IIPPacket.cs +++ b/Esiur/Net/Packets/IIPPacket.cs @@ -37,10 +37,10 @@ class IIPPacket : Packet public uint CallbackId { get; set; } public IIPPacketMethod Method { get; set; } - public IIPPacketRequest Request { get; set; } - public IIPPacketReply Reply { get; set; } + public IIPPacketRequest Request { get; set; } + public IIPPacketReply Reply { get; set; } - public IIPPacketNotification Notification { get; set; } + public IIPPacketNotification Notification { get; set; } public byte Extension { get; set; } @@ -57,12 +57,12 @@ class IIPPacket : Packet public override string ToString() { - return Method switch + return Method switch { IIPPacketMethod.Notification => $"{Method} {Notification}", - IIPPacketMethod.Request => $"{Method} {Request}", - IIPPacketMethod.Reply => $"{Method} {Reply}", - IIPPacketMethod.Extension => $"{Method} {Extension}", + IIPPacketMethod.Request => $"{Method} {Request}", + IIPPacketMethod.Reply => $"{Method} {Reply}", + IIPPacketMethod.Extension => $"{Method} {Extension}", _ => $"{Method}" }; } @@ -124,12 +124,12 @@ class IIPPacket : Packet if (NotEnough(offset, ends, 1)) return -dataLengthNeeded; - (var size, DataType) = ParsedTDU.Parse(data, offset, ends); + DataType = ParsedTDU.Parse(data, offset, ends); - if (DataType == null) - return -(int)size; + if (DataType.Value.Class == TDUClass.Invalid) + return -(int)DataType.Value.TotalLength; - offset += (uint)size; + offset += (uint)DataType.Value.TotalLength; } else {