mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
Make Lidgren Use Spans & Shared Pool (#1140)
* make lidgren use spans everywhere where it can convert custom pooling to shared array pool impl add unit tests for read/write add native socket extensions to socket so we can legit pass spans for SendTo/ReceiveFrom bump version in lidgren csproj replace some random "% 8" w/ "& 7" more minor nullability hacks to fix static analysis complaints made receiving packets use span minor native sockets refactor to use pinvoke add read/write constrained/prealloc'd bit stream impl to lidgren and update usages fixed missing stream cleanup remove outstanding stream cleanup since it refs buffer thru the class, can't read some other buf apply suggestions from code review remove unsafe cruft * add tests to gh actions * make stats use interpolation in tostring and remove m_bytesAllocated since it's all in the shared pool now * this pr still open so fuck it stats, human readability, faster BitsToHold methods * add api compatible version of ReadBytes * rename ReadOnlyStreamWrapper -> ReadOnlyWrapperStream rename WriteOnlyStreamWrapper -> WriteOnlyWrapperStream add AppendViaStream, AppenderStream impl add and update documentation on read/write bytes methods also fix some goofs
This commit is contained in:
4
.github/workflows/build-test.yml
vendored
4
.github/workflows/build-test.yml
vendored
@@ -21,5 +21,7 @@ jobs:
|
||||
run: dotnet restore
|
||||
- name: Build
|
||||
run: dotnet build --no-restore /p:WarningsAsErrors=nullable
|
||||
- name: Test
|
||||
- name: Test Engine
|
||||
run: dotnet test --no-build Robust.UnitTesting/Robust.UnitTesting.csproj -v n
|
||||
- name: Test Lidgren
|
||||
run: dotnet test --no-build Lidgren.Network.UnitTests/Lidgren.Network.UnitTests.csproj -v n
|
||||
|
||||
19
Lidgren.Network.UnitTests/Lidgren.Network.UnitTests.csproj
Normal file
19
Lidgren.Network.UnitTests/Lidgren.Network.UnitTests.csproj
Normal file
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="nunit" Version="3.12.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Lidgren.Network\Lidgren.Network.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
229
Lidgren.Network.UnitTests/ReadWriteTests.cs
Normal file
229
Lidgren.Network.UnitTests/ReadWriteTests.cs
Normal file
@@ -0,0 +1,229 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using static System.Reflection.BindingFlags;
|
||||
|
||||
namespace Lidgren.Network.UnitTests
|
||||
{
|
||||
|
||||
public class ReadWriteTests : TestsBase
|
||||
{
|
||||
|
||||
[Test]
|
||||
public void TestSmallMessage1()
|
||||
{
|
||||
var peer = Peer;
|
||||
var msg = peer.CreateMessage();
|
||||
|
||||
msg.Write(false);
|
||||
msg.Write(-3, 6);
|
||||
msg.Write(true);
|
||||
|
||||
msg.WritePadBits();
|
||||
|
||||
var data = msg.Buffer;
|
||||
|
||||
var inc = CreateIncomingMessage(data, msg.LengthBits);
|
||||
|
||||
var boolean = inc.ReadBoolean();
|
||||
Assert.IsFalse(boolean);
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
||||
|
||||
var value = inc.ReadInt32(6);
|
||||
Assert.AreEqual(-3, value);
|
||||
|
||||
boolean = inc.ReadBoolean();
|
||||
Assert.IsTrue(boolean);
|
||||
|
||||
inc.SkipPadBits();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSmallMessage2()
|
||||
{
|
||||
var peer = Peer;
|
||||
var msg = peer.CreateMessage();
|
||||
|
||||
msg.Write(false);
|
||||
msg.Write(-3, 6);
|
||||
msg.Write(42);
|
||||
msg.Write("duke of earl");
|
||||
msg.Write((byte) 43);
|
||||
msg.Write((ushort) 44);
|
||||
msg.Write(UInt64.MaxValue, 64);
|
||||
var c = msg.WriteVariableInt64(long.MaxValue >> 16);
|
||||
msg.Write(true);
|
||||
Assert.AreEqual(7, c);
|
||||
|
||||
msg.WritePadBits();
|
||||
|
||||
var data = msg.Buffer;
|
||||
|
||||
var inc = CreateIncomingMessage(data, msg.LengthBits);
|
||||
|
||||
var boolean = inc.ReadBoolean();
|
||||
Assert.IsFalse(boolean);
|
||||
|
||||
var value = inc.ReadInt32(6);
|
||||
Assert.AreEqual(-3, value);
|
||||
|
||||
value = inc.ReadInt32();
|
||||
Assert.AreEqual(42, value);
|
||||
|
||||
var ok = inc.ReadString(out var strResult);
|
||||
Assert.IsTrue(ok, "Read/write failure");
|
||||
Assert.AreEqual("duke of earl", strResult);
|
||||
|
||||
var byteVal = inc.ReadByte();
|
||||
Assert.AreEqual(43,byteVal);
|
||||
|
||||
Assert.AreEqual((ushort) 44, inc.ReadUInt16(), "Read/write failure");
|
||||
|
||||
Assert.AreEqual(UInt64.MaxValue, inc.ReadUInt64(64), "Read/write failure");
|
||||
|
||||
var longVal = inc.ReadVariableInt64();
|
||||
Assert.AreEqual(long.MaxValue >> 16, longVal);
|
||||
|
||||
boolean = inc.ReadBoolean();
|
||||
Assert.IsTrue(boolean);
|
||||
|
||||
inc.SkipPadBits();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestComplexMessage()
|
||||
{
|
||||
var peer = Peer;
|
||||
var msg = peer.CreateMessage();
|
||||
|
||||
msg.Write(false);
|
||||
msg.Write(-3, 6);
|
||||
msg.Write(42);
|
||||
msg.Write("duke of earl");
|
||||
msg.Write((byte) 43);
|
||||
msg.Write((ushort) 44);
|
||||
msg.Write(UInt64.MaxValue, 64);
|
||||
msg.Write(true);
|
||||
|
||||
msg.WritePadBits();
|
||||
|
||||
var bcnt = 0;
|
||||
|
||||
msg.Write(567845.0f);
|
||||
msg.WriteVariableInt32(2115998022);
|
||||
msg.Write(46.0);
|
||||
msg.Write((ushort) 14, 9);
|
||||
bcnt += msg.WriteVariableInt32(-47);
|
||||
msg.WriteVariableInt32(470000);
|
||||
msg.WriteVariableUInt32(48);
|
||||
bcnt += msg.WriteVariableInt64(-49);
|
||||
|
||||
Assert.AreEqual(2, bcnt, "WriteVariable* wrote too many bytes!");
|
||||
|
||||
var data = msg.Buffer;
|
||||
|
||||
var inc = CreateIncomingMessage(data, msg.LengthBits);
|
||||
|
||||
var boolean = inc.ReadBoolean();
|
||||
Assert.IsFalse(boolean);
|
||||
var value = inc.ReadInt32(6);
|
||||
Assert.AreEqual(-3, value);
|
||||
value = inc.ReadInt32();
|
||||
Assert.AreEqual(42, value);
|
||||
|
||||
var ok = inc.ReadString(out var strResult);
|
||||
Assert.IsTrue(ok, "Read/write failure");
|
||||
Assert.AreEqual("duke of earl", strResult);
|
||||
|
||||
var byteVal = inc.ReadByte();
|
||||
Assert.AreEqual(43, byteVal);
|
||||
|
||||
Assert.AreEqual((ushort) 44, inc.ReadUInt16(), "Read/write failure");
|
||||
|
||||
Assert.AreEqual(UInt64.MaxValue, inc.ReadUInt64(64), "Read/write failure");
|
||||
|
||||
boolean = inc.ReadBoolean();
|
||||
Assert.IsTrue(boolean);
|
||||
|
||||
inc.SkipPadBits();
|
||||
|
||||
Assert.AreEqual(567845.0f, inc.ReadSingle());
|
||||
Assert.AreEqual(2115998022, inc.ReadVariableInt32());
|
||||
Assert.AreEqual(46.0, inc.ReadDouble());
|
||||
Assert.AreEqual(14, inc.ReadUInt32(9));
|
||||
Assert.AreEqual(-47, inc.ReadVariableInt32());
|
||||
Assert.AreEqual(470000, inc.ReadVariableInt32());
|
||||
Assert.AreEqual(48, inc.ReadVariableUInt32());
|
||||
Assert.AreEqual(-49, inc.ReadVariableInt64());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWriteAllFields()
|
||||
{
|
||||
var peer = Peer;
|
||||
|
||||
var msg = peer.CreateMessage();
|
||||
|
||||
var tmp = peer.CreateMessage();
|
||||
tmp.Write((int) 42, 14);
|
||||
|
||||
msg.Write(tmp);
|
||||
msg.Write(tmp);
|
||||
|
||||
Assert.AreEqual(tmp.LengthBits * 2, msg.LengthBits, "NetOutgoingMessage.Write(NetOutgoingMessage) failed!");
|
||||
|
||||
tmp = peer.CreateMessage();
|
||||
|
||||
var testItem = new TestItem
|
||||
{
|
||||
Number = 42,
|
||||
Name = "Hallon",
|
||||
Age = 8.2f
|
||||
};
|
||||
|
||||
tmp.WriteAllFields(testItem, Public | Instance);
|
||||
|
||||
var data = tmp.Buffer;
|
||||
|
||||
var inc = CreateIncomingMessage(data, tmp.LengthBits);
|
||||
|
||||
var readTestItem = new TestItem();
|
||||
inc.ReadAllFields(readTestItem, Public | Instance);
|
||||
|
||||
Assert.AreEqual(42, readTestItem.Number);
|
||||
Assert.AreEqual("Hallon", readTestItem.Name);
|
||||
Assert.AreEqual(8.2f, readTestItem.Age);
|
||||
|
||||
// test aligned WriteBytes/ReadBytes
|
||||
msg = peer.CreateMessage();
|
||||
var tmparr = new byte[] {5, 6, 7, 8, 9};
|
||||
msg.Write(tmparr);
|
||||
|
||||
inc = CreateIncomingMessage(msg.Buffer, msg.LengthBits);
|
||||
var result = inc.ReadBytes(stackalloc byte[tmparr.Length]);
|
||||
|
||||
for (var i = 0; i < tmparr.Length; i++)
|
||||
{
|
||||
Assert.AreEqual(result[i], tmparr[i], "readbytes fail");
|
||||
}
|
||||
}
|
||||
|
||||
public class TestItemBase
|
||||
{
|
||||
|
||||
public int Number;
|
||||
|
||||
}
|
||||
|
||||
public class TestItem : TestItemBase
|
||||
{
|
||||
|
||||
public float Age;
|
||||
|
||||
public string Name;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
76
Lidgren.Network.UnitTests/TestsBase.cs
Normal file
76
Lidgren.Network.UnitTests/TestsBase.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using static System.Reflection.BindingFlags;
|
||||
|
||||
namespace Lidgren.Network.UnitTests
|
||||
{
|
||||
|
||||
public abstract class TestsBase
|
||||
{
|
||||
|
||||
protected NetPeerConfiguration Config;
|
||||
|
||||
protected NetPeer Peer;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Config = new NetPeerConfiguration(GetType().Name)
|
||||
{
|
||||
EnableUPnP = true
|
||||
};
|
||||
Peer = new NetPeer(Config);
|
||||
Peer.Start();
|
||||
|
||||
TestContext.Out.WriteLine("Unique identifier is " + NetUtility.ToHexString(Peer.UniqueIdentifier));
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
=> Peer.Shutdown("Unit test teardown.");
|
||||
|
||||
protected static NetIncomingMessage CreateIncomingMessage(byte[] fromData, int bitLength)
|
||||
{
|
||||
var inc = (NetIncomingMessage) Activator.CreateInstance(typeof(NetIncomingMessage), true);
|
||||
typeof(NetIncomingMessage).GetField("m_buf", NonPublic | Instance)!
|
||||
.SetValue(inc, fromData);
|
||||
typeof(NetIncomingMessage).GetField("m_bitLength", NonPublic | Instance)!
|
||||
.SetValue(inc, bitLength);
|
||||
return inc;
|
||||
}
|
||||
|
||||
protected static string ToBinaryString(ulong value, int bits, bool includeSpaces)
|
||||
{
|
||||
var numSpaces = Math.Max(0, bits / 8 - 1);
|
||||
if (includeSpaces == false)
|
||||
{
|
||||
numSpaces = 0;
|
||||
}
|
||||
|
||||
var bdr = new StringBuilder(bits + numSpaces);
|
||||
for (var i = 0; i < bits + numSpaces; i++)
|
||||
{
|
||||
bdr.Append(' ');
|
||||
}
|
||||
|
||||
for (var i = 0; i < bits; i++)
|
||||
{
|
||||
var shifted = value >> i;
|
||||
var isSet = (shifted & 1) != 0;
|
||||
|
||||
var pos = bits - 1 - i;
|
||||
if (includeSpaces)
|
||||
{
|
||||
pos += Math.Max(0, pos / 8);
|
||||
}
|
||||
|
||||
bdr[pos] = isSet ? '1' : '0';
|
||||
}
|
||||
|
||||
return bdr.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,7 +25,7 @@ namespace Lidgren.Network
|
||||
SetKey(key);
|
||||
}
|
||||
|
||||
public NetAESEncryption(NetPeer peer, byte[] data, int offset, int count)
|
||||
public NetAESEncryption(NetPeer peer, ReadOnlySpan<byte> data, int offset, int count)
|
||||
#if UNITY
|
||||
: base(peer, new RijndaelManaged())
|
||||
#else
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Lidgren.Network
|
||||
@@ -8,8 +9,6 @@ namespace Lidgren.Network
|
||||
/// </summary>
|
||||
public abstract class NetBlockEncryptionBase : NetEncryption
|
||||
{
|
||||
// temporary space for one block to avoid reallocating every time
|
||||
private byte[] m_tmp;
|
||||
|
||||
/// <summary>
|
||||
/// Block size in bytes for this cipher
|
||||
@@ -22,7 +21,6 @@ namespace Lidgren.Network
|
||||
public NetBlockEncryptionBase(NetPeer peer)
|
||||
: base(peer)
|
||||
{
|
||||
m_tmp = new byte[BlockSize];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -33,16 +31,20 @@ namespace Lidgren.Network
|
||||
int payloadBitLength = msg.LengthBits;
|
||||
int numBytes = msg.LengthBytes;
|
||||
int blockSize = BlockSize;
|
||||
int numBlocks = (int)Math.Ceiling((double)numBytes / (double)blockSize);
|
||||
Span<byte> tmp = stackalloc byte[BlockSize];
|
||||
int numBlocks = (int)Math.Ceiling(numBytes / (double)blockSize);
|
||||
int dstSize = numBlocks * blockSize;
|
||||
|
||||
msg.EnsureBufferSize(dstSize * 8 + (4 * 8)); // add 4 bytes for payload length at end
|
||||
msg.LengthBits = dstSize * 8; // length will automatically adjust +4 bytes when payload length is written
|
||||
|
||||
var dataSpan = msg.m_data;
|
||||
for(int i=0;i<numBlocks;i++)
|
||||
{
|
||||
EncryptBlock(msg.m_data, (i * blockSize), m_tmp);
|
||||
Buffer.BlockCopy(m_tmp, 0, msg.m_data, (i * blockSize), m_tmp.Length);
|
||||
// TODO: honestly is tmp even necessary here?
|
||||
EncryptBlock(dataSpan, (i * blockSize), tmp);
|
||||
//Buffer.BlockCopy(m_tmp, 0, dataSpan, (i * blockSize), m_tmp.Length);
|
||||
tmp.CopyTo(dataSpan.Slice(i * blockSize, tmp.Length));
|
||||
}
|
||||
|
||||
// add true payload length last
|
||||
@@ -60,18 +62,22 @@ namespace Lidgren.Network
|
||||
{
|
||||
int numEncryptedBytes = msg.LengthBytes - 4; // last 4 bytes is true bit length
|
||||
int blockSize = BlockSize;
|
||||
Span<byte> tmp = stackalloc byte[BlockSize];
|
||||
int numBlocks = numEncryptedBytes / blockSize;
|
||||
if (numBlocks * blockSize != numEncryptedBytes)
|
||||
return false;
|
||||
|
||||
var dataSpan = msg.m_data;
|
||||
for (int i = 0; i < numBlocks; i++)
|
||||
{
|
||||
DecryptBlock(msg.m_data, (i * blockSize), m_tmp);
|
||||
Buffer.BlockCopy(m_tmp, 0, msg.m_data, (i * blockSize), m_tmp.Length);
|
||||
// TODO: honestly is tmp even necessary here?
|
||||
DecryptBlock(dataSpan, (i * blockSize), tmp);
|
||||
//Buffer.BlockCopy(m_tmp, 0, dataSpan, (i * blockSize), m_tmp.Length);
|
||||
tmp.CopyTo(dataSpan.Slice(i * blockSize, tmp.Length));
|
||||
}
|
||||
|
||||
// read 32 bits of true payload length
|
||||
uint realSize = NetBitWriter.ReadUInt32(msg.m_data, 32, (numEncryptedBytes * 8));
|
||||
uint realSize = NetBitWriter.ReadUInt32(dataSpan, 32, (numEncryptedBytes * 8));
|
||||
msg.m_bitLength = (int)realSize;
|
||||
return true;
|
||||
}
|
||||
@@ -79,11 +85,13 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Encrypt a block of bytes
|
||||
/// </summary>
|
||||
protected abstract void EncryptBlock(byte[] source, int sourceOffset, byte[] destination);
|
||||
protected abstract void EncryptBlock(ReadOnlySpan<byte> source, int sourceOffset, Span<byte> destination);
|
||||
|
||||
/// <summary>
|
||||
/// Decrypt a block of bytes
|
||||
/// </summary>
|
||||
protected abstract void DecryptBlock(byte[] source, int sourceOffset, byte[] destination);
|
||||
protected abstract void DecryptBlock(ReadOnlySpan<byte> source, int sourceOffset, Span<byte> destination);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@ using System.Security.Cryptography;
|
||||
|
||||
namespace Lidgren.Network
|
||||
{
|
||||
|
||||
public abstract class NetCryptoProviderBase : NetEncryption
|
||||
{
|
||||
|
||||
protected SymmetricAlgorithm m_algorithm;
|
||||
|
||||
public NetCryptoProviderBase(NetPeer peer, SymmetricAlgorithm algo)
|
||||
@@ -16,9 +18,10 @@ namespace Lidgren.Network
|
||||
m_algorithm.GenerateIV();
|
||||
}
|
||||
|
||||
public override void SetKey(byte[] data, int offset, int count)
|
||||
public override void SetKey(ReadOnlySpan<byte> data, int offset, int count)
|
||||
{
|
||||
int len = m_algorithm.Key.Length;
|
||||
// ReSharper disable once SuggestVarOrType_Elsewhere
|
||||
var key = new byte[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
key[i] = data[offset + (i % count)];
|
||||
@@ -35,9 +38,9 @@ namespace Lidgren.Network
|
||||
{
|
||||
int unEncLenBits = msg.LengthBits;
|
||||
|
||||
var ms = new MemoryStream();
|
||||
using var ms = new MemoryStream(msg.LengthBytes);
|
||||
var cs = new CryptoStream(ms, m_algorithm.CreateEncryptor(), CryptoStreamMode.Write);
|
||||
cs.Write(msg.m_data, 0, msg.LengthBytes);
|
||||
cs.Write(msg.m_data.Slice(0, msg.LengthBytes));
|
||||
cs.Close();
|
||||
|
||||
// get results
|
||||
@@ -46,7 +49,7 @@ namespace Lidgren.Network
|
||||
|
||||
msg.EnsureBufferSize((arr.Length + 4) * 8);
|
||||
msg.LengthBits = 0; // reset write pointer
|
||||
msg.Write((uint)unEncLenBits);
|
||||
msg.Write((uint) unEncLenBits);
|
||||
msg.Write(arr);
|
||||
msg.LengthBits = (arr.Length + 4) * 8;
|
||||
|
||||
@@ -55,23 +58,26 @@ namespace Lidgren.Network
|
||||
|
||||
public override bool Decrypt(NetIncomingMessage msg)
|
||||
{
|
||||
int unEncLenBits = (int)msg.ReadUInt32();
|
||||
int unEncLenBits = (int) msg.ReadUInt32();
|
||||
|
||||
var ms = new MemoryStream(msg.m_data, 4, msg.LengthBytes - 4);
|
||||
byte[] result;
|
||||
using var ms = new MemoryStream(msg.m_buf, 4, msg.LengthBytes - 4);
|
||||
var cs = new CryptoStream(ms, m_algorithm.CreateDecryptor(), CryptoStreamMode.Read);
|
||||
|
||||
var byteLen = NetUtility.BytesToHoldBits(unEncLenBits);
|
||||
var result = m_peer.GetStorage(byteLen);
|
||||
result = m_peer.GetStorage(byteLen);
|
||||
cs.Read(result, 0, byteLen);
|
||||
cs.Close();
|
||||
|
||||
// TODO: recycle existing msg
|
||||
|
||||
msg.m_data = result;
|
||||
msg.m_buf = result;
|
||||
msg.m_bitLength = unEncLenBits;
|
||||
msg.m_readPosition = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Lidgren.Network
|
||||
@@ -11,17 +12,18 @@ namespace Lidgren.Network
|
||||
{
|
||||
}
|
||||
|
||||
protected abstract CryptoStream GetEncryptStream(MemoryStream ms);
|
||||
protected abstract CryptoStream GetEncryptStream(Stream ms);
|
||||
|
||||
protected abstract CryptoStream GetDecryptStream(MemoryStream ms);
|
||||
protected abstract CryptoStream GetDecryptStream(Stream ms);
|
||||
|
||||
public override bool Encrypt(NetOutgoingMessage msg)
|
||||
{
|
||||
int unEncLenBits = msg.LengthBits;
|
||||
|
||||
var ms = new MemoryStream();
|
||||
using var ms = new MemoryStream(msg.LengthBytes);
|
||||
var cs = GetEncryptStream(ms);
|
||||
cs.Write(msg.m_data, 0, msg.LengthBytes);
|
||||
var dataSpan = msg.m_data;
|
||||
cs.Write(dataSpan.Slice(0,msg.LengthBytes));
|
||||
cs.Close();
|
||||
|
||||
// get results
|
||||
@@ -41,8 +43,8 @@ namespace Lidgren.Network
|
||||
{
|
||||
int unEncLenBits = (int)msg.ReadUInt32();
|
||||
|
||||
var ms = new MemoryStream(msg.m_data, 4, msg.LengthBytes - 4);
|
||||
var cs = GetDecryptStream(ms);
|
||||
using var ums = new MemoryStream(msg.m_buf, 4, msg.LengthBytes - 4);
|
||||
var cs = GetDecryptStream(ums);
|
||||
|
||||
var result = m_peer.GetStorage(unEncLenBits);
|
||||
cs.Read(result, 0, NetUtility.BytesToHoldBits(unEncLenBits));
|
||||
@@ -50,7 +52,7 @@ namespace Lidgren.Network
|
||||
|
||||
// TODO: recycle existing msg
|
||||
|
||||
msg.m_data = result;
|
||||
msg.m_buf = result;
|
||||
msg.m_bitLength = unEncLenBits;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Lidgren.Network
|
||||
SetKey(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
public abstract void SetKey(byte[] data, int offset, int count);
|
||||
public abstract void SetKey(ReadOnlySpan<byte> data, int offset, int count);
|
||||
|
||||
/// <summary>
|
||||
/// Encrypt an outgoing message in place
|
||||
|
||||
@@ -9,21 +9,21 @@ namespace Lidgren.Network
|
||||
/// </summary>
|
||||
public class NetXorEncryption : NetEncryption
|
||||
{
|
||||
private byte[] m_key;
|
||||
private Memory<byte> m_key;
|
||||
|
||||
/// <summary>
|
||||
/// NetXorEncryption constructor
|
||||
/// </summary>
|
||||
public NetXorEncryption(NetPeer peer, byte[] key)
|
||||
public NetXorEncryption(NetPeer peer, Memory<byte> key)
|
||||
: base(peer)
|
||||
{
|
||||
m_key = key;
|
||||
}
|
||||
|
||||
public override void SetKey(byte[] data, int offset, int count)
|
||||
public override void SetKey(ReadOnlySpan<byte> data, int offset, int count)
|
||||
{
|
||||
m_key = new byte[count];
|
||||
Array.Copy(data, offset, m_key, 0, count);
|
||||
data.CopyTo(m_key.Span);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -41,10 +41,12 @@ namespace Lidgren.Network
|
||||
public override bool Encrypt(NetOutgoingMessage msg)
|
||||
{
|
||||
int numBytes = msg.LengthBytes;
|
||||
var dataSpan = msg.m_data;
|
||||
var keySpan = m_key.Span;
|
||||
for (int i = 0; i < numBytes; i++)
|
||||
{
|
||||
int offset = i % m_key.Length;
|
||||
msg.m_data[i] = (byte)(msg.m_data[i] ^ m_key[offset]);
|
||||
int offset = i % keySpan.Length;
|
||||
dataSpan[i] = (byte)(dataSpan[i] ^ keySpan[offset]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -55,10 +57,12 @@ namespace Lidgren.Network
|
||||
public override bool Decrypt(NetIncomingMessage msg)
|
||||
{
|
||||
int numBytes = msg.LengthBytes;
|
||||
var keySpan = m_key.Span;
|
||||
var dataSpan = msg.m_data;
|
||||
for (int i = 0; i < numBytes; i++)
|
||||
{
|
||||
int offset = i % m_key.Length;
|
||||
msg.m_data[i] = (byte)(msg.m_data[i] ^ m_key[offset]);
|
||||
int offset = i % keySpan.Length;
|
||||
dataSpan[i] = (byte)(dataSpan[i] ^ keySpan[offset]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -79,17 +79,11 @@ namespace Lidgren.Network
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// String to hash for key
|
||||
/// </summary>
|
||||
public NetXtea(NetPeer peer, string key)
|
||||
: this(peer, NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(key)), 32)
|
||||
public override void SetKey(ReadOnlySpan<byte> data, int offset, int length)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SetKey(byte[] data, int offset, int length)
|
||||
{
|
||||
var key = NetUtility.ComputeSHAHash(data, offset, length);
|
||||
// ReSharper disable once SuggestVarOrType_Elsewhere
|
||||
Span<byte> key = stackalloc byte[32];
|
||||
NetUtility.ComputeSHAHash(data.Slice( offset, length), key);
|
||||
NetException.Assert(key.Length >= 16);
|
||||
SetKey(key, 0, 16);
|
||||
}
|
||||
@@ -97,7 +91,7 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Encrypts a block of bytes
|
||||
/// </summary>
|
||||
protected override void EncryptBlock(byte[] source, int sourceOffset, byte[] destination)
|
||||
protected override void EncryptBlock(ReadOnlySpan<byte> source, int sourceOffset, Span<byte> destination)
|
||||
{
|
||||
uint v0 = BytesToUInt(source, sourceOffset);
|
||||
uint v1 = BytesToUInt(source, sourceOffset + 4);
|
||||
@@ -117,7 +111,7 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Decrypts a block of bytes
|
||||
/// </summary>
|
||||
protected override void DecryptBlock(byte[] source, int sourceOffset, byte[] destination)
|
||||
protected override void DecryptBlock(ReadOnlySpan<byte> source, int sourceOffset, Span<byte> destination)
|
||||
{
|
||||
// Pack bytes into integers
|
||||
uint v0 = BytesToUInt(source, sourceOffset);
|
||||
@@ -135,7 +129,7 @@ namespace Lidgren.Network
|
||||
return;
|
||||
}
|
||||
|
||||
private static uint BytesToUInt(byte[] bytes, int offset)
|
||||
private static uint BytesToUInt(ReadOnlySpan<byte> bytes, int offset)
|
||||
{
|
||||
uint retval = (uint)(bytes[offset] << 24);
|
||||
retval |= (uint)(bytes[++offset] << 16);
|
||||
@@ -143,7 +137,7 @@ namespace Lidgren.Network
|
||||
return (retval | bytes[++offset]);
|
||||
}
|
||||
|
||||
private static void UIntToBytes(uint value, byte[] destination, int destinationOffset)
|
||||
private static void UIntToBytes(uint value, Span<byte> destination, int destinationOffset)
|
||||
{
|
||||
destination[destinationOffset++] = (byte)(value >> 24);
|
||||
destination[destinationOffset++] = (byte)(value >> 16);
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Platforms>AnyCPU</Platforms>
|
||||
<SonarQubeExclude>true</SonarQubeExclude>
|
||||
<DefineConstants>$(DefineConstants);USE_RELEASE_STATISTICS</DefineConstants>
|
||||
<DefineConstants>$(DefineConstants);USE_RELEASE_STATISTICS;UNSAFE</DefineConstants>
|
||||
<LangVersion>8</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -256,13 +256,13 @@ namespace Lidgren.Network
|
||||
}
|
||||
|
||||
public NetBigInteger(
|
||||
byte[] bytes)
|
||||
ReadOnlySpan<byte> bytes)
|
||||
: this(bytes, 0, bytes.Length)
|
||||
{
|
||||
}
|
||||
|
||||
public NetBigInteger(
|
||||
byte[] bytes,
|
||||
ReadOnlySpan<byte> bytes,
|
||||
int offset,
|
||||
int length)
|
||||
{
|
||||
@@ -287,7 +287,7 @@ namespace Lidgren.Network
|
||||
else
|
||||
{
|
||||
int numBytes = end - iBval;
|
||||
byte[] inverse = new byte[numBytes];
|
||||
Span<byte> inverse = stackalloc byte[numBytes];
|
||||
|
||||
int index = 0;
|
||||
while (index < numBytes)
|
||||
@@ -316,7 +316,7 @@ namespace Lidgren.Network
|
||||
}
|
||||
|
||||
private static int[] MakeMagnitude(
|
||||
byte[] bytes,
|
||||
ReadOnlySpan<byte> bytes,
|
||||
int offset,
|
||||
int length)
|
||||
{
|
||||
@@ -374,14 +374,14 @@ namespace Lidgren.Network
|
||||
|
||||
public NetBigInteger(
|
||||
int sign,
|
||||
byte[] bytes)
|
||||
ReadOnlySpan<byte> bytes)
|
||||
: this(sign, bytes, 0, bytes.Length)
|
||||
{
|
||||
}
|
||||
|
||||
public NetBigInteger(
|
||||
int sign,
|
||||
byte[] bytes,
|
||||
ReadOnlySpan<byte> bytes,
|
||||
int offset,
|
||||
int length)
|
||||
{
|
||||
|
||||
@@ -19,10 +19,11 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR TH
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Lidgren.Network
|
||||
{
|
||||
@@ -34,7 +35,7 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Read 1-8 bits from a buffer into a byte
|
||||
/// </summary>
|
||||
public static byte ReadByte(byte[] fromBuffer, int numberOfBits, int readBitOffset)
|
||||
public static byte ReadByte(ReadOnlySpan<byte> fromBuffer, int numberOfBits, int readBitOffset)
|
||||
{
|
||||
NetException.Assert(((numberOfBits > 0) && (numberOfBits < 9)), "Read() can only read between 1 and 8 bits");
|
||||
|
||||
@@ -67,14 +68,16 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Read several bytes from a buffer
|
||||
/// </summary>
|
||||
public static void ReadBytes(byte[] fromBuffer, int numberOfBytes, int readBitOffset, byte[] destination, int destinationByteOffset)
|
||||
public static void ReadBytes(ReadOnlySpan<byte> fromBuffer, int numberOfBytes, int readBitOffset, Span<byte> destination, int destinationByteOffset)
|
||||
{
|
||||
int readPtr = readBitOffset >> 3;
|
||||
int startReadAtIndex = readBitOffset - (readPtr * 8); // (readBitOffset % 8);
|
||||
|
||||
if (startReadAtIndex == 0)
|
||||
{
|
||||
Buffer.BlockCopy(fromBuffer, readPtr, destination, destinationByteOffset, numberOfBytes);
|
||||
//Buffer.BlockCopy(fromBuffer, readPtr, destination, destinationByteOffset, numberOfBytes);
|
||||
fromBuffer.Slice(readPtr,numberOfBytes)
|
||||
.CopyTo(destination.Slice(destinationByteOffset, numberOfBytes));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -93,14 +96,48 @@ namespace Lidgren.Network
|
||||
|
||||
destination[destinationByteOffset++] = (byte)(b | (second << secondPartLen));
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
/// <summary>
|
||||
/// Read several bytes from a buffer
|
||||
/// </summary>
|
||||
public static void ReadBytes(ReadOnlySpan<byte> fromBuffer, int readBitOffset, Span<byte> destination)
|
||||
{
|
||||
var destinationByteOffset = 0;
|
||||
var numberOfBytes = (fromBuffer.Length << 3 - readBitOffset) >> 3;
|
||||
int readPtr = readBitOffset >> 3;
|
||||
int startReadAtIndex = readBitOffset - (readPtr * 8); // (readBitOffset % 8);
|
||||
|
||||
if (startReadAtIndex == 0)
|
||||
{
|
||||
//Buffer.BlockCopy(fromBuffer, readPtr, destination, destinationByteOffset, numberOfBytes);
|
||||
fromBuffer.Slice(readPtr,numberOfBytes)
|
||||
.CopyTo(destination.Slice(0, numberOfBytes));
|
||||
return;
|
||||
}
|
||||
|
||||
int secondPartLen = 8 - startReadAtIndex;
|
||||
int secondMask = 255 >> secondPartLen;
|
||||
|
||||
for (int i = 0; i < numberOfBytes; i++)
|
||||
{
|
||||
// mask away unused bits lower than (right of) relevant bits in byte
|
||||
int b = fromBuffer[readPtr] >> startReadAtIndex;
|
||||
|
||||
readPtr++;
|
||||
|
||||
// mask away unused bits higher than (left of) relevant bits in second byte
|
||||
int second = fromBuffer[readPtr] & secondMask;
|
||||
|
||||
destination[destinationByteOffset++] = (byte)(b | (second << secondPartLen));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write 0-8 bits of data to buffer
|
||||
/// </summary>
|
||||
public static void WriteByte(byte source, int numberOfBits, byte[] destination, int destBitOffset)
|
||||
public static void WriteByte(byte source, int numberOfBits, Span<byte> destination, int destBitOffset)
|
||||
{
|
||||
if (numberOfBits == 0)
|
||||
return;
|
||||
@@ -149,18 +186,63 @@ namespace Lidgren.Network
|
||||
(source >> bitsFree)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Zero a number of bits
|
||||
/// </summary>
|
||||
public static void Zero(int numberOfBits, Span<byte> destination, int destBitOffset)
|
||||
{
|
||||
var dstBytePtr = destBitOffset >> 3;
|
||||
var firstPartLen = destBitOffset & 7;
|
||||
var numberOfBytes = numberOfBits >> 3;
|
||||
var endBits = numberOfBits & 7;
|
||||
|
||||
if (firstPartLen == 0)
|
||||
{
|
||||
destination.Slice(destBitOffset / 8, numberOfBytes).Fill(0);
|
||||
|
||||
if (endBits <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var endByteSpan = destination.Slice(numberOfBytes, 1);
|
||||
|
||||
endByteSpan[0] = (byte) (endByteSpan[0] & ~(byte.MaxValue >> (8 - endBits)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var lastPartLen = 8 - firstPartLen;
|
||||
|
||||
destination[dstBytePtr] &= (byte)(255 >> lastPartLen);
|
||||
|
||||
++dstBytePtr;
|
||||
|
||||
destination.Slice(dstBytePtr, numberOfBytes-2).Fill(0);
|
||||
|
||||
dstBytePtr = numberOfBytes - 2;
|
||||
|
||||
destination[dstBytePtr] &= (byte)(255 << firstPartLen);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
|
||||
/// <summary>
|
||||
/// Write several whole bytes
|
||||
/// </summary>
|
||||
public static void WriteBytes(byte[] source, int sourceByteOffset, int numberOfBytes, byte[] destination, int destBitOffset)
|
||||
public static void WriteBytes(ReadOnlySpan<byte> source, int sourceByteOffset, int numberOfBytes, Span<byte> destination, int destBitOffset)
|
||||
{
|
||||
int dstBytePtr = destBitOffset >> 3;
|
||||
int firstPartLen = (destBitOffset % 8);
|
||||
int firstPartLen = (destBitOffset & 7);
|
||||
|
||||
if (firstPartLen == 0)
|
||||
{
|
||||
Buffer.BlockCopy(source, sourceByteOffset, destination, dstBytePtr, numberOfBytes);
|
||||
//Buffer.BlockCopy(source, sourceByteOffset, destination, dstBytePtr, numberOfBytes);
|
||||
source.Slice(sourceByteOffset,numberOfBytes)
|
||||
.CopyTo(destination.Slice(dstBytePtr, numberOfBytes));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -180,31 +262,57 @@ namespace Lidgren.Network
|
||||
destination[dstBytePtr] &= (byte)(255 << firstPartLen); // clear before writing
|
||||
destination[dstBytePtr] |= (byte)(src >> lastPartLen); // write second half
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
/// <summary>
|
||||
/// Write several whole bytes
|
||||
/// </summary>
|
||||
public static void WriteBytes(ReadOnlySpan<byte> source, Span<byte> destination, int destBitOffset)
|
||||
{
|
||||
int sourceByteOffset = 0;
|
||||
int numberOfBytes = source.Length;
|
||||
int dstBytePtr = destBitOffset >> 3;
|
||||
int firstPartLen = destBitOffset & 7;
|
||||
|
||||
if (firstPartLen == 0)
|
||||
{
|
||||
//Buffer.BlockCopy(source, sourceByteOffset, destination, dstBytePtr, numberOfBytes);
|
||||
source
|
||||
.CopyTo(destination.Slice(dstBytePtr, numberOfBytes));
|
||||
return;
|
||||
}
|
||||
|
||||
int lastPartLen = 8 - firstPartLen;
|
||||
|
||||
for (int i = 0; i < numberOfBytes; i++)
|
||||
{
|
||||
byte src = source[sourceByteOffset + i];
|
||||
|
||||
// write last part of this byte
|
||||
destination[dstBytePtr] &= (byte)(255 >> lastPartLen); // clear before writing
|
||||
destination[dstBytePtr] |= (byte)(src << firstPartLen); // write first half
|
||||
|
||||
dstBytePtr++;
|
||||
|
||||
// write first part of next byte
|
||||
destination[dstBytePtr] &= (byte)(255 << firstPartLen); // clear before writing
|
||||
destination[dstBytePtr] |= (byte)(src >> lastPartLen); // write second half
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an unsigned 16 bit integer
|
||||
/// </summary>
|
||||
[CLSCompliant(false)]
|
||||
#if UNSAFE
|
||||
public static unsafe ushort ReadUInt16(byte[] fromBuffer, int numberOfBits, int readBitOffset)
|
||||
public static ushort ReadUInt16(ReadOnlySpan<byte> fromBuffer, int numberOfBits, int readBitOffset)
|
||||
{
|
||||
Debug.Assert(((numberOfBits > 0) && (numberOfBits <= 16)), "ReadUInt16() can only read between 1 and 16 bits");
|
||||
|
||||
if (numberOfBits == 16 && ((readBitOffset % 8) == 0))
|
||||
if (numberOfBits == 16 && ((readBitOffset & 7) == 0))
|
||||
{
|
||||
fixed (byte* ptr = &(fromBuffer[readBitOffset / 8]))
|
||||
{
|
||||
return *(((ushort*)ptr));
|
||||
}
|
||||
return MemoryMarshal.Read<ushort>(fromBuffer.Slice(readBitOffset / 8));
|
||||
}
|
||||
#else
|
||||
public static ushort ReadUInt16(byte[] fromBuffer, int numberOfBits, int readBitOffset)
|
||||
{
|
||||
Debug.Assert(((numberOfBits > 0) && (numberOfBits <= 16)), "ReadUInt16() can only read between 1 and 16 bits");
|
||||
#endif
|
||||
ushort returnValue;
|
||||
if (numberOfBits <= 8)
|
||||
{
|
||||
@@ -220,38 +328,27 @@ namespace Lidgren.Network
|
||||
returnValue |= (ushort)(ReadByte(fromBuffer, numberOfBits, readBitOffset) << 8);
|
||||
}
|
||||
|
||||
#if BIGENDIAN
|
||||
// reorder bytes
|
||||
uint retVal = returnValue;
|
||||
retVal = ((retVal & 0x0000ff00) >> 8) | ((retVal & 0x000000ff) << 8);
|
||||
return (ushort)retVal;
|
||||
#else
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
return BinaryPrimitives.ReverseEndianness(returnValue);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of bits into an UInt32
|
||||
/// </summary>
|
||||
[CLSCompliant(false)]
|
||||
#if UNSAFE
|
||||
public static unsafe uint ReadUInt32(byte[] fromBuffer, int numberOfBits, int readBitOffset)
|
||||
public static uint ReadUInt32(ReadOnlySpan<byte> fromBuffer, int numberOfBits, int readBitOffset)
|
||||
{
|
||||
NetException.Assert(((numberOfBits > 0) && (numberOfBits <= 32)), "ReadUInt32() can only read between 1 and 32 bits");
|
||||
|
||||
if (numberOfBits == 32 && ((readBitOffset % 8) == 0))
|
||||
if (numberOfBits == 32 && ((readBitOffset & 7) == 0))
|
||||
{
|
||||
fixed (byte* ptr = &(fromBuffer[readBitOffset / 8]))
|
||||
{
|
||||
return *(((uint*)ptr));
|
||||
}
|
||||
return MemoryMarshal.Read<uint>(fromBuffer.Slice(readBitOffset / 8));
|
||||
}
|
||||
#else
|
||||
|
||||
public static uint ReadUInt32(byte[] fromBuffer, int numberOfBits, int readBitOffset)
|
||||
{
|
||||
NetException.Assert(((numberOfBits > 0) && (numberOfBits <= 32)), "ReadUInt32() can only read between 1 and 32 bits");
|
||||
#endif
|
||||
|
||||
uint returnValue;
|
||||
if (numberOfBits <= 8)
|
||||
{
|
||||
@@ -284,16 +381,12 @@ namespace Lidgren.Network
|
||||
|
||||
returnValue |= (uint)(ReadByte(fromBuffer, numberOfBits, readBitOffset) << 24);
|
||||
|
||||
#if BIGENDIAN
|
||||
// reorder bytes
|
||||
return
|
||||
((returnValue & 0xff000000) >> 24) |
|
||||
((returnValue & 0x00ff0000) >> 8) |
|
||||
((returnValue & 0x0000ff00) << 8) |
|
||||
((returnValue & 0x000000ff) << 24);
|
||||
#else
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
return BinaryPrimitives.ReverseEndianness(returnValue);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
#endif
|
||||
}
|
||||
|
||||
//[CLSCompliant(false)]
|
||||
@@ -303,74 +396,76 @@ namespace Lidgren.Network
|
||||
/// Writes an unsigned 16 bit integer
|
||||
/// </summary>
|
||||
[CLSCompliant(false)]
|
||||
public static void WriteUInt16(ushort source, int numberOfBits, byte[] destination, int destinationBitOffset)
|
||||
public static void WriteUInt16(ushort source, int numberOfBits, Span<byte> destination, int destinationBitOffset)
|
||||
{
|
||||
if (numberOfBits == 0)
|
||||
return;
|
||||
|
||||
NetException.Assert((numberOfBits >= 0 && numberOfBits <= 16), "numberOfBits must be between 0 and 16");
|
||||
#if BIGENDIAN
|
||||
// reorder bytes
|
||||
uint intSource = source;
|
||||
intSource = ((intSource & 0x0000ff00) >> 8) | ((intSource & 0x000000ff) << 8);
|
||||
source = (ushort)intSource;
|
||||
#endif
|
||||
if (numberOfBits <= 8)
|
||||
{
|
||||
NetBitWriter.WriteByte((byte)source, numberOfBits, destination, destinationBitOffset);
|
||||
return;
|
||||
}
|
||||
|
||||
NetBitWriter.WriteByte((byte)source, 8, destination, destinationBitOffset);
|
||||
NetException.Assert((numberOfBits >= 0 && numberOfBits <= 16), "numberOfBits must be between 0 and 16");
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
source = BinaryPrimitives.ReverseEndianness(source);
|
||||
}
|
||||
|
||||
|
||||
if (numberOfBits <= 8)
|
||||
{
|
||||
WriteByte((byte)source, numberOfBits, destination, destinationBitOffset);
|
||||
return;
|
||||
}
|
||||
|
||||
WriteByte((byte)source, 8, destination, destinationBitOffset);
|
||||
|
||||
numberOfBits -= 8;
|
||||
if (numberOfBits > 0)
|
||||
NetBitWriter.WriteByte((byte)(source >> 8), numberOfBits, destination, destinationBitOffset + 8);
|
||||
|
||||
WriteByte((byte)(source >> 8), numberOfBits, destination, destinationBitOffset + 8);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified number of bits into a byte array
|
||||
/// </summary>
|
||||
[CLSCompliant(false)]
|
||||
public static int WriteUInt32(uint source, int numberOfBits, byte[] destination, int destinationBitOffset)
|
||||
public static int WriteUInt32(uint source, int numberOfBits, Span<byte> destination, int destinationBitOffset)
|
||||
{
|
||||
#if BIGENDIAN
|
||||
// reorder bytes
|
||||
source = ((source & 0xff000000) >> 24) |
|
||||
((source & 0x00ff0000) >> 8) |
|
||||
((source & 0x0000ff00) << 8) |
|
||||
((source & 0x000000ff) << 24);
|
||||
#endif
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
source = BinaryPrimitives.ReverseEndianness(source);
|
||||
}
|
||||
|
||||
int returnValue = destinationBitOffset + numberOfBits;
|
||||
if (numberOfBits <= 8)
|
||||
{
|
||||
NetBitWriter.WriteByte((byte)source, numberOfBits, destination, destinationBitOffset);
|
||||
WriteByte((byte)source, numberOfBits, destination, destinationBitOffset);
|
||||
return returnValue;
|
||||
}
|
||||
NetBitWriter.WriteByte((byte)source, 8, destination, destinationBitOffset);
|
||||
|
||||
WriteByte((byte)source, 8, destination, destinationBitOffset);
|
||||
destinationBitOffset += 8;
|
||||
numberOfBits -= 8;
|
||||
|
||||
if (numberOfBits <= 8)
|
||||
{
|
||||
NetBitWriter.WriteByte((byte)(source >> 8), numberOfBits, destination, destinationBitOffset);
|
||||
WriteByte((byte)(source >> 8), numberOfBits, destination, destinationBitOffset);
|
||||
return returnValue;
|
||||
}
|
||||
NetBitWriter.WriteByte((byte)(source >> 8), 8, destination, destinationBitOffset);
|
||||
|
||||
WriteByte((byte)(source >> 8), 8, destination, destinationBitOffset);
|
||||
destinationBitOffset += 8;
|
||||
numberOfBits -= 8;
|
||||
|
||||
if (numberOfBits <= 8)
|
||||
{
|
||||
NetBitWriter.WriteByte((byte)(source >> 16), numberOfBits, destination, destinationBitOffset);
|
||||
WriteByte((byte)(source >> 16), numberOfBits, destination, destinationBitOffset);
|
||||
return returnValue;
|
||||
}
|
||||
NetBitWriter.WriteByte((byte)(source >> 16), 8, destination, destinationBitOffset);
|
||||
|
||||
WriteByte((byte)(source >> 16), 8, destination, destinationBitOffset);
|
||||
destinationBitOffset += 8;
|
||||
numberOfBits -= 8;
|
||||
|
||||
NetBitWriter.WriteByte((byte)(source >> 24), numberOfBits, destination, destinationBitOffset);
|
||||
WriteByte((byte)(source >> 24), numberOfBits, destination, destinationBitOffset);
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
@@ -378,89 +473,90 @@ namespace Lidgren.Network
|
||||
/// Writes the specified number of bits into a byte array
|
||||
/// </summary>
|
||||
[CLSCompliant(false)]
|
||||
public static int WriteUInt64(ulong source, int numberOfBits, byte[] destination, int destinationBitOffset)
|
||||
public static int WriteUInt64(ulong source, int numberOfBits, Span<byte> destination, int destinationBitOffset)
|
||||
{
|
||||
#if BIGENDIAN
|
||||
source = ((source & 0xff00000000000000L) >> 56) |
|
||||
((source & 0x00ff000000000000L) >> 40) |
|
||||
((source & 0x0000ff0000000000L) >> 24) |
|
||||
((source & 0x000000ff00000000L) >> 8) |
|
||||
((source & 0x00000000ff000000L) << 8) |
|
||||
((source & 0x0000000000ff0000L) << 24) |
|
||||
((source & 0x000000000000ff00L) << 40) |
|
||||
((source & 0x00000000000000ffL) << 56);
|
||||
#endif
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
source = BinaryPrimitives.ReverseEndianness(source);
|
||||
|
||||
|
||||
int returnValue = destinationBitOffset + numberOfBits;
|
||||
if (numberOfBits <= 8)
|
||||
{
|
||||
NetBitWriter.WriteByte((byte)source, numberOfBits, destination, destinationBitOffset);
|
||||
WriteByte((byte)source, numberOfBits, destination, destinationBitOffset);
|
||||
return returnValue;
|
||||
}
|
||||
NetBitWriter.WriteByte((byte)source, 8, destination, destinationBitOffset);
|
||||
|
||||
WriteByte((byte)source, 8, destination, destinationBitOffset);
|
||||
destinationBitOffset += 8;
|
||||
numberOfBits -= 8;
|
||||
|
||||
if (numberOfBits <= 8)
|
||||
{
|
||||
NetBitWriter.WriteByte((byte)(source >> 8), numberOfBits, destination, destinationBitOffset);
|
||||
WriteByte((byte)(source >> 8), numberOfBits, destination, destinationBitOffset);
|
||||
return returnValue;
|
||||
}
|
||||
NetBitWriter.WriteByte((byte)(source >> 8), 8, destination, destinationBitOffset);
|
||||
|
||||
WriteByte((byte)(source >> 8), 8, destination, destinationBitOffset);
|
||||
destinationBitOffset += 8;
|
||||
numberOfBits -= 8;
|
||||
|
||||
if (numberOfBits <= 8)
|
||||
{
|
||||
NetBitWriter.WriteByte((byte)(source >> 16), numberOfBits, destination, destinationBitOffset);
|
||||
WriteByte((byte)(source >> 16), numberOfBits, destination, destinationBitOffset);
|
||||
return returnValue;
|
||||
}
|
||||
NetBitWriter.WriteByte((byte)(source >> 16), 8, destination, destinationBitOffset);
|
||||
|
||||
WriteByte((byte)(source >> 16), 8, destination, destinationBitOffset);
|
||||
destinationBitOffset += 8;
|
||||
numberOfBits -= 8;
|
||||
|
||||
if (numberOfBits <= 8)
|
||||
{
|
||||
NetBitWriter.WriteByte((byte)(source >> 24), numberOfBits, destination, destinationBitOffset);
|
||||
WriteByte((byte)(source >> 24), numberOfBits, destination, destinationBitOffset);
|
||||
return returnValue;
|
||||
}
|
||||
NetBitWriter.WriteByte((byte)(source >> 24), 8, destination, destinationBitOffset);
|
||||
|
||||
WriteByte((byte)(source >> 24), 8, destination, destinationBitOffset);
|
||||
destinationBitOffset += 8;
|
||||
numberOfBits -= 8;
|
||||
|
||||
if (numberOfBits <= 8)
|
||||
{
|
||||
NetBitWriter.WriteByte((byte)(source >> 32), numberOfBits, destination, destinationBitOffset);
|
||||
WriteByte((byte)(source >> 32), numberOfBits, destination, destinationBitOffset);
|
||||
return returnValue;
|
||||
}
|
||||
NetBitWriter.WriteByte((byte)(source >> 32), 8, destination, destinationBitOffset);
|
||||
|
||||
WriteByte((byte)(source >> 32), 8, destination, destinationBitOffset);
|
||||
destinationBitOffset += 8;
|
||||
numberOfBits -= 8;
|
||||
|
||||
if (numberOfBits <= 8)
|
||||
{
|
||||
NetBitWriter.WriteByte((byte)(source >> 40), numberOfBits, destination, destinationBitOffset);
|
||||
WriteByte((byte)(source >> 40), numberOfBits, destination, destinationBitOffset);
|
||||
return returnValue;
|
||||
}
|
||||
NetBitWriter.WriteByte((byte)(source >> 40), 8, destination, destinationBitOffset);
|
||||
|
||||
WriteByte((byte)(source >> 40), 8, destination, destinationBitOffset);
|
||||
destinationBitOffset += 8;
|
||||
numberOfBits -= 8;
|
||||
|
||||
if (numberOfBits <= 8)
|
||||
{
|
||||
NetBitWriter.WriteByte((byte)(source >> 48), numberOfBits, destination, destinationBitOffset);
|
||||
WriteByte((byte)(source >> 48), numberOfBits, destination, destinationBitOffset);
|
||||
return returnValue;
|
||||
}
|
||||
NetBitWriter.WriteByte((byte)(source >> 48), 8, destination, destinationBitOffset);
|
||||
|
||||
WriteByte((byte)(source >> 48), 8, destination, destinationBitOffset);
|
||||
destinationBitOffset += 8;
|
||||
numberOfBits -= 8;
|
||||
|
||||
if (numberOfBits <= 8)
|
||||
{
|
||||
NetBitWriter.WriteByte((byte)(source >> 56), numberOfBits, destination, destinationBitOffset);
|
||||
WriteByte((byte)(source >> 56), numberOfBits, destination, destinationBitOffset);
|
||||
return returnValue;
|
||||
}
|
||||
NetBitWriter.WriteByte((byte)(source >> 56), 8, destination, destinationBitOffset);
|
||||
|
||||
WriteByte((byte)(source >> 56), 8, destination, destinationBitOffset);
|
||||
destinationBitOffset += 8;
|
||||
numberOfBits -= 8;
|
||||
|
||||
@@ -476,10 +572,10 @@ namespace Lidgren.Network
|
||||
/// </summary>
|
||||
/// <returns>number of bytes written</returns>
|
||||
[CLSCompliant(false)]
|
||||
public static int WriteVariableUInt32(byte[] intoBuffer, int offset, uint value)
|
||||
public static int WriteVariableUInt32(Span<byte> intoBuffer, int offset, uint value)
|
||||
{
|
||||
int retval = 0;
|
||||
uint num1 = (uint)value;
|
||||
uint num1 = value;
|
||||
while (num1 >= 0x80)
|
||||
{
|
||||
intoBuffer[offset + retval] = (byte)(num1 | 0x80);
|
||||
@@ -494,7 +590,7 @@ namespace Lidgren.Network
|
||||
/// Reads a UInt32 written using WriteUnsignedVarInt(); will increment offset!
|
||||
/// </summary>
|
||||
[CLSCompliant(false)]
|
||||
public static uint ReadVariableUInt32(byte[] buffer, ref int offset)
|
||||
public static uint ReadVariableUInt32(Span<byte> buffer, ref int offset)
|
||||
{
|
||||
int num1 = 0;
|
||||
int num2 = 0;
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Gets the internal data buffer
|
||||
/// </summary>
|
||||
public byte[] PeekDataBuffer() { return m_data; }
|
||||
public Span<byte> PeekDataBuffer() { return m_data; }
|
||||
|
||||
//
|
||||
// 1 bit
|
||||
@@ -79,25 +79,25 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes without advancing the read pointer
|
||||
/// </summary>
|
||||
public byte[] PeekBytes(int numberOfBytes)
|
||||
public Span<byte> PeekBytes(Span<byte> bytes)
|
||||
{
|
||||
var numberOfBytes = bytes.Length;
|
||||
NetException.Assert(m_bitLength - m_readPosition >= (numberOfBytes * 8), c_readOverflowError);
|
||||
|
||||
byte[] retval = new byte[numberOfBytes];
|
||||
NetBitWriter.ReadBytes(m_data, numberOfBytes, m_readPosition, retval, 0);
|
||||
return retval;
|
||||
NetBitWriter.ReadBytes(m_data, numberOfBytes, m_readPosition, bytes, 0);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes without advancing the read pointer
|
||||
/// </summary>
|
||||
public void PeekBytes(byte[] into, int offset, int numberOfBytes)
|
||||
public Span<byte> PeekBytes(Span<byte> into, int offset, int numberOfBytes)
|
||||
{
|
||||
NetException.Assert(m_bitLength - m_readPosition >= (numberOfBytes * 8), c_readOverflowError);
|
||||
NetException.Assert(offset + numberOfBytes <= into.Length);
|
||||
|
||||
NetBitWriter.ReadBytes(m_data, numberOfBytes, m_readPosition, into, offset);
|
||||
return;
|
||||
return into;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -271,12 +271,12 @@ namespace Lidgren.Network
|
||||
|
||||
if ((m_readPosition & 7) == 0) // read directly
|
||||
{
|
||||
float retval = BitConverter.ToSingle(m_data, m_readPosition >> 3);
|
||||
float retval = BitConverter.ToSingle(m_data.Slice( m_readPosition >> 3));
|
||||
return retval;
|
||||
}
|
||||
|
||||
byte[] bytes = PeekBytes(4);
|
||||
return BitConverter.ToSingle(bytes, 0);
|
||||
var bytes = PeekBytes(stackalloc byte[4]);
|
||||
return BitConverter.ToSingle(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -289,12 +289,12 @@ namespace Lidgren.Network
|
||||
if ((m_readPosition & 7) == 0) // read directly
|
||||
{
|
||||
// read directly
|
||||
double retval = BitConverter.ToDouble(m_data, m_readPosition >> 3);
|
||||
double retval = BitConverter.ToDouble(m_data.Slice( m_readPosition >> 3));
|
||||
return retval;
|
||||
}
|
||||
|
||||
byte[] bytes = PeekBytes(8);
|
||||
return BitConverter.ToDouble(bytes, 0);
|
||||
var bytes = PeekBytes(stackalloc byte[8]);
|
||||
return BitConverter.ToDouble(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using System.Net;
|
||||
@@ -17,18 +18,16 @@ namespace Lidgren.Network
|
||||
public partial class NetBuffer
|
||||
{
|
||||
private const string c_readOverflowError = "Trying to read past the buffer size - likely caused by mismatching Write/Reads, different size or order.";
|
||||
private const int c_bufferSize = 64; // Min 8 to hold anything but strings. Increase it if readed strings usally don't fit inside the buffer
|
||||
private static object s_buffer;
|
||||
private const string c_writeOverflowError = "Trying to write past the end of a constrained buffer - likely caused by mismatching Write/Reads, different size or order.";
|
||||
|
||||
/// <summary>
|
||||
/// Reads a boolean value (stored as a single bit) written using Write(bool)
|
||||
/// </summary>
|
||||
public bool ReadBoolean()
|
||||
{
|
||||
NetException.Assert(m_bitLength - m_readPosition >= 1, c_readOverflowError);
|
||||
byte retval = NetBitWriter.ReadByte(m_data, 1, m_readPosition);
|
||||
var retval = PeekBoolean();
|
||||
m_readPosition += 1;
|
||||
return (retval > 0 ? true : false);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -36,8 +35,7 @@ namespace Lidgren.Network
|
||||
/// </summary>
|
||||
public byte ReadByte()
|
||||
{
|
||||
NetException.Assert(m_bitLength - m_readPosition >= 8, c_readOverflowError);
|
||||
byte retval = NetBitWriter.ReadByte(m_data, 8, m_readPosition);
|
||||
var retval = PeekByte();
|
||||
m_readPosition += 8;
|
||||
return retval;
|
||||
}
|
||||
@@ -52,7 +50,8 @@ namespace Lidgren.Network
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
result = NetBitWriter.ReadByte(m_data, 8, m_readPosition);
|
||||
|
||||
result = PeekByte();
|
||||
m_readPosition += 8;
|
||||
return true;
|
||||
}
|
||||
@@ -63,10 +62,9 @@ namespace Lidgren.Network
|
||||
[CLSCompliant(false)]
|
||||
public sbyte ReadSByte()
|
||||
{
|
||||
NetException.Assert(m_bitLength - m_readPosition >= 8, c_readOverflowError);
|
||||
byte retval = NetBitWriter.ReadByte(m_data, 8, m_readPosition);
|
||||
sbyte retval = PeekSByte();
|
||||
m_readPosition += 8;
|
||||
return (sbyte)retval;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -74,65 +72,76 @@ namespace Lidgren.Network
|
||||
/// </summary>
|
||||
public byte ReadByte(int numberOfBits)
|
||||
{
|
||||
NetException.Assert(numberOfBits > 0 && numberOfBits <= 8, "ReadByte(bits) can only read between 1 and 8 bits");
|
||||
byte retval = NetBitWriter.ReadByte(m_data, numberOfBits, m_readPosition);
|
||||
byte retval = PeekByte(numberOfBits);
|
||||
m_readPosition += numberOfBits;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes
|
||||
/// Creates a stream out of a constrained region of the buffer for reading.
|
||||
/// </summary>
|
||||
public byte[] ReadBytes(int numberOfBytes)
|
||||
/// <param name="byteLength">The length of the constrained region in bytes.</param>
|
||||
/// <returns>A readable constrained buffer region wrapped by a stream.</returns>
|
||||
public Stream ReadAsStream(int byteLength)
|
||||
{
|
||||
NetException.Assert(m_bitLength - m_readPosition + 7 >= (numberOfBytes * 8), c_readOverflowError);
|
||||
|
||||
byte[] retval = new byte[numberOfBytes];
|
||||
NetBitWriter.ReadBytes(m_data, numberOfBytes, m_readPosition, retval, 0);
|
||||
m_readPosition += (8 * numberOfBytes);
|
||||
return retval;
|
||||
var bitLength = byteLength*8;
|
||||
var stream = new ReadOnlyWrapperStream(this, m_readPosition, bitLength);
|
||||
m_readPosition += bitLength;
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes and returns true for success
|
||||
/// </summary>
|
||||
public bool ReadBytes(int numberOfBytes, out byte[] result)
|
||||
{
|
||||
if (m_bitLength - m_readPosition + 7 < (numberOfBytes * 8))
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
result = new byte[numberOfBytes];
|
||||
NetBitWriter.ReadBytes(m_data, numberOfBytes, m_readPosition, result, 0);
|
||||
m_readPosition += (8 * numberOfBytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes into a preallocated array
|
||||
/// Prefer using <see cref="NetBuffer.ReadBytes(Span{byte})" /> instead.
|
||||
/// Reads the specified number of bytes into a allocated array.
|
||||
/// </summary>
|
||||
/// <param name="into">The destination array</param>
|
||||
/// <param name="offset">The offset where to start writing in the destination array</param>
|
||||
/// <param name="numberOfBytes">The number of bytes to read</param>
|
||||
public void ReadBytes(byte[] into, int offset, int numberOfBytes)
|
||||
/// <returns>The same as <paramref name="into"/></returns>
|
||||
//[Obsolete("Use the Span parameter version of ReadBytes instead")]
|
||||
public byte[] ReadBytes(int length)
|
||||
{
|
||||
NetException.Assert(m_bitLength - m_readPosition + 7 >= (numberOfBytes * 8), c_readOverflowError);
|
||||
NetException.Assert(offset + numberOfBytes <= into.Length);
|
||||
|
||||
NetBitWriter.ReadBytes(m_data, numberOfBytes, m_readPosition, into, offset);
|
||||
m_readPosition += (8 * numberOfBytes);
|
||||
return;
|
||||
var into = new byte[length];
|
||||
PeekBytes(into);
|
||||
m_readPosition += 8 * into.Length;
|
||||
return into;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of bits into a preallocated array
|
||||
/// Reads the specified number of bytes into a pre-allocated array.
|
||||
/// </summary>
|
||||
/// <param name="into">The destination</param>
|
||||
/// <returns>The same as <paramref name="into"/></returns>
|
||||
public Span<byte> ReadBytes(Span<byte> into)
|
||||
{
|
||||
var bytes = PeekBytes(into);
|
||||
m_readPosition += 8 * into.Length;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of bytes into a pre-allocated array.
|
||||
/// </summary>
|
||||
/// <param name="into">The destination array</param>
|
||||
/// <param name="offset">The offset where to start writing in the destination array</param>
|
||||
/// <param name="numberOfBytes">The number of bytes to read</param>
|
||||
/// <returns>The same as <paramref name="into"/></returns>
|
||||
//[Obsolete("Use Span alternative instead with slicing.")]
|
||||
public Span<byte> ReadBytes(Span<byte> into, int offset, int numberOfBytes)
|
||||
{
|
||||
var bytes = PeekBytes(into, offset, numberOfBytes);
|
||||
m_readPosition += 8 * numberOfBytes;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the specified number of bits into a pre-allocated array.
|
||||
/// </summary>
|
||||
/// <param name="into">The destination array</param>
|
||||
/// <param name="offset">The offset where to start writing in the destination array</param>
|
||||
/// <param name="numberOfBits">The number of bits to read</param>
|
||||
public void ReadBits(byte[] into, int offset, int numberOfBits)
|
||||
//[Obsolete("Use Span alternative instead with slicing.")]
|
||||
public Span<byte> ReadBits(Span<byte> into, int offset, int numberOfBits)
|
||||
{
|
||||
NetException.Assert(m_bitLength - m_readPosition >= numberOfBits, c_readOverflowError);
|
||||
NetException.Assert(offset + NetUtility.BytesToHoldBits(numberOfBits) <= into.Length);
|
||||
@@ -146,7 +155,7 @@ namespace Lidgren.Network
|
||||
if (extraBits > 0)
|
||||
into[offset + numberOfWholeBytes] = ReadByte(extraBits);
|
||||
|
||||
return;
|
||||
return into.Slice(offset,(numberOfBits+extraBits) >> 3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -154,10 +163,9 @@ namespace Lidgren.Network
|
||||
/// </summary>
|
||||
public Int16 ReadInt16()
|
||||
{
|
||||
NetException.Assert(m_bitLength - m_readPosition >= 16, c_readOverflowError);
|
||||
uint retval = NetBitWriter.ReadUInt16(m_data, 16, m_readPosition);
|
||||
var retval = PeekInt16();
|
||||
m_readPosition += 16;
|
||||
return (short)retval;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -166,8 +174,7 @@ namespace Lidgren.Network
|
||||
[CLSCompliant(false)]
|
||||
public UInt16 ReadUInt16()
|
||||
{
|
||||
NetException.Assert(m_bitLength - m_readPosition >= 16, c_readOverflowError);
|
||||
uint retval = NetBitWriter.ReadUInt16(m_data, 16, m_readPosition);
|
||||
var retval = PeekUInt16();
|
||||
m_readPosition += 16;
|
||||
return (ushort)retval;
|
||||
}
|
||||
@@ -177,8 +184,7 @@ namespace Lidgren.Network
|
||||
/// </summary>
|
||||
public Int32 ReadInt32()
|
||||
{
|
||||
NetException.Assert(m_bitLength - m_readPosition >= 32, c_readOverflowError);
|
||||
uint retval = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
|
||||
var retval = PeekInt32();
|
||||
m_readPosition += 32;
|
||||
return (Int32)retval;
|
||||
}
|
||||
@@ -195,7 +201,7 @@ namespace Lidgren.Network
|
||||
return false;
|
||||
}
|
||||
|
||||
result = (Int32)NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
|
||||
result = PeekInt32();
|
||||
m_readPosition += 32;
|
||||
return true;
|
||||
}
|
||||
@@ -205,26 +211,9 @@ namespace Lidgren.Network
|
||||
/// </summary>
|
||||
public Int32 ReadInt32(int numberOfBits)
|
||||
{
|
||||
NetException.Assert(numberOfBits > 0 && numberOfBits <= 32, "ReadInt32(bits) can only read between 1 and 32 bits");
|
||||
NetException.Assert(m_bitLength - m_readPosition >= numberOfBits, c_readOverflowError);
|
||||
|
||||
uint retval = NetBitWriter.ReadUInt32(m_data, numberOfBits, m_readPosition);
|
||||
var retval = PeekInt32(numberOfBits);
|
||||
m_readPosition += numberOfBits;
|
||||
|
||||
if (numberOfBits == 32)
|
||||
return (int)retval;
|
||||
|
||||
int signBit = 1 << (numberOfBits - 1);
|
||||
if ((retval & signBit) == 0)
|
||||
return (int)retval; // positive
|
||||
|
||||
// negative
|
||||
unchecked
|
||||
{
|
||||
uint mask = ((uint)-1) >> (33 - numberOfBits);
|
||||
uint tmp = (retval & mask) + 1;
|
||||
return -((int)tmp);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -233,8 +222,7 @@ namespace Lidgren.Network
|
||||
[CLSCompliant(false)]
|
||||
public UInt32 ReadUInt32()
|
||||
{
|
||||
NetException.Assert(m_bitLength - m_readPosition >= 32, c_readOverflowError);
|
||||
uint retval = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
|
||||
var retval = PeekUInt32();
|
||||
m_readPosition += 32;
|
||||
return retval;
|
||||
}
|
||||
@@ -250,7 +238,7 @@ namespace Lidgren.Network
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
result = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
|
||||
result = PeekUInt32();
|
||||
m_readPosition += 32;
|
||||
return true;
|
||||
}
|
||||
@@ -261,10 +249,7 @@ namespace Lidgren.Network
|
||||
[CLSCompliant(false)]
|
||||
public UInt32 ReadUInt32(int numberOfBits)
|
||||
{
|
||||
NetException.Assert(numberOfBits > 0 && numberOfBits <= 32, "ReadUInt32(bits) can only read between 1 and 32 bits");
|
||||
//NetException.Assert(m_bitLength - m_readBitPtr >= numberOfBits, "tried to read past buffer size");
|
||||
|
||||
UInt32 retval = NetBitWriter.ReadUInt32(m_data, numberOfBits, m_readPosition);
|
||||
var retval = PeekUInt32(numberOfBits);
|
||||
m_readPosition += numberOfBits;
|
||||
return retval;
|
||||
}
|
||||
@@ -275,15 +260,8 @@ namespace Lidgren.Network
|
||||
[CLSCompliant(false)]
|
||||
public UInt64 ReadUInt64()
|
||||
{
|
||||
NetException.Assert(m_bitLength - m_readPosition >= 64, c_readOverflowError);
|
||||
|
||||
ulong low = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
|
||||
m_readPosition += 32;
|
||||
ulong high = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
|
||||
|
||||
ulong retval = low + (high << 32);
|
||||
|
||||
m_readPosition += 32;
|
||||
var retval = PeekUInt64();
|
||||
m_readPosition += 64;
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -307,19 +285,7 @@ namespace Lidgren.Network
|
||||
[CLSCompliant(false)]
|
||||
public UInt64 ReadUInt64(int numberOfBits)
|
||||
{
|
||||
NetException.Assert(numberOfBits > 0 && numberOfBits <= 64, "ReadUInt64(bits) can only read between 1 and 64 bits");
|
||||
NetException.Assert(m_bitLength - m_readPosition >= numberOfBits, c_readOverflowError);
|
||||
|
||||
ulong retval;
|
||||
if (numberOfBits <= 32)
|
||||
{
|
||||
retval = (ulong)NetBitWriter.ReadUInt32(m_data, numberOfBits, m_readPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = NetBitWriter.ReadUInt32(m_data, 32, m_readPosition);
|
||||
retval |= (UInt64)NetBitWriter.ReadUInt32(m_data, numberOfBits - 32, m_readPosition + 32) << 32;
|
||||
}
|
||||
var retval = PeekUInt64(numberOfBits);
|
||||
m_readPosition += numberOfBits;
|
||||
return retval;
|
||||
}
|
||||
@@ -348,18 +314,9 @@ namespace Lidgren.Network
|
||||
{
|
||||
NetException.Assert(m_bitLength - m_readPosition >= 32, c_readOverflowError);
|
||||
|
||||
if ((m_readPosition & 7) == 0) // read directly
|
||||
{
|
||||
float retval = BitConverter.ToSingle(m_data, m_readPosition >> 3);
|
||||
m_readPosition += 32;
|
||||
return retval;
|
||||
}
|
||||
|
||||
byte[] bytes = (byte[]) Interlocked.Exchange(ref s_buffer, null) ?? new byte[c_bufferSize];
|
||||
ReadBytes(bytes, 0, 4);
|
||||
float res = BitConverter.ToSingle(bytes, 0);
|
||||
s_buffer = bytes;
|
||||
return res;
|
||||
var retval = PeekSingle();
|
||||
m_readPosition += 32;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -373,17 +330,7 @@ namespace Lidgren.Network
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((m_readPosition & 7) == 0) // read directly
|
||||
{
|
||||
result = BitConverter.ToSingle(m_data, m_readPosition >> 3);
|
||||
m_readPosition += 32;
|
||||
return true;
|
||||
}
|
||||
|
||||
byte[] bytes = (byte[]) Interlocked.Exchange(ref s_buffer, null) ?? new byte[c_bufferSize];
|
||||
ReadBytes(bytes, 0, 4);
|
||||
result = BitConverter.ToSingle(bytes, 0);
|
||||
s_buffer = bytes;
|
||||
result = ReadSingle();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -394,18 +341,8 @@ namespace Lidgren.Network
|
||||
{
|
||||
NetException.Assert(m_bitLength - m_readPosition >= 64, c_readOverflowError);
|
||||
|
||||
if ((m_readPosition & 7) == 0) // read directly
|
||||
{
|
||||
// read directly
|
||||
double retval = BitConverter.ToDouble(m_data, m_readPosition >> 3);
|
||||
m_readPosition += 64;
|
||||
return retval;
|
||||
}
|
||||
|
||||
byte[] bytes = (byte[]) Interlocked.Exchange(ref s_buffer, null) ?? new byte[c_bufferSize];
|
||||
ReadBytes(bytes, 0, 8);
|
||||
double res = BitConverter.ToDouble(bytes, 0);
|
||||
s_buffer = bytes;
|
||||
var res = PeekDouble();
|
||||
m_readPosition += 64;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -599,21 +536,13 @@ namespace Lidgren.Network
|
||||
if ((m_readPosition & 7) == 0)
|
||||
{
|
||||
// read directly
|
||||
string retval = System.Text.Encoding.UTF8.GetString(m_data, m_readPosition >> 3, byteLen);
|
||||
string retval = Encoding.UTF8.GetString(m_data.Slice( m_readPosition >> 3, byteLen));
|
||||
m_readPosition += (8 * byteLen);
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (byteLen <= c_bufferSize) {
|
||||
byte[] buffer = (byte[]) Interlocked.Exchange(ref s_buffer, null) ?? new byte[c_bufferSize];
|
||||
ReadBytes(buffer, 0, byteLen);
|
||||
string retval = Encoding.UTF8.GetString(buffer, 0, byteLen);
|
||||
s_buffer = buffer;
|
||||
return retval;
|
||||
} else {
|
||||
byte[] bytes = ReadBytes(byteLen);
|
||||
return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
|
||||
}
|
||||
var bytes = ReadBytes(stackalloc byte[byteLen]);
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -643,19 +572,13 @@ namespace Lidgren.Network
|
||||
if ((m_readPosition & 7) == 0)
|
||||
{
|
||||
// read directly
|
||||
result = System.Text.Encoding.UTF8.GetString(m_data, m_readPosition >> 3, (int)byteLen);
|
||||
result = Encoding.UTF8.GetString(m_data.Slice(m_readPosition >> 3, (int)byteLen));
|
||||
m_readPosition += (8 * (int)byteLen);
|
||||
return true;
|
||||
}
|
||||
|
||||
byte[] bytes;
|
||||
if (ReadBytes((int)byteLen, out bytes) == false)
|
||||
{
|
||||
result = String.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
result = System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Length);
|
||||
var bytes = ReadBytes(stackalloc byte[(int)byteLen]);
|
||||
result = Encoding.UTF8.GetString(bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -679,7 +602,7 @@ namespace Lidgren.Network
|
||||
public NetEndPoint ReadIPEndPoint()
|
||||
{
|
||||
byte len = ReadByte();
|
||||
byte[] addressBytes = ReadBytes(len);
|
||||
var addressBytes = ReadBytes(stackalloc byte[len]);
|
||||
int port = (int)ReadUInt16();
|
||||
|
||||
var address = NetUtility.CreateAddressFromBytes(addressBytes);
|
||||
|
||||
@@ -19,7 +19,10 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR TH
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
@@ -55,14 +58,20 @@ namespace Lidgren.Network
|
||||
public void EnsureBufferSize(int numberOfBits)
|
||||
{
|
||||
int byteLen = ((numberOfBits + 7) >> 3);
|
||||
if (m_data == null)
|
||||
if (m_buf == null)
|
||||
{
|
||||
m_data = new byte[byteLen + c_overAllocateAmount];
|
||||
m_buf = ArrayPool<byte>.Shared.Rent(byteLen + c_overAllocateAmount);
|
||||
return;
|
||||
}
|
||||
if (m_data.Length < byteLen)
|
||||
Array.Resize<byte>(ref m_data, byteLen + c_overAllocateAmount);
|
||||
return;
|
||||
|
||||
if (m_buf.Length < byteLen)
|
||||
{
|
||||
var pool = ArrayPool<byte>.Shared;
|
||||
var oldBuf = m_buf;
|
||||
m_buf = pool.Rent(byteLen + c_overAllocateAmount);
|
||||
new Span<byte>(oldBuf).CopyTo(m_buf);
|
||||
pool.Return(oldBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,14 +80,20 @@ namespace Lidgren.Network
|
||||
internal void InternalEnsureBufferSize(int numberOfBits)
|
||||
{
|
||||
int byteLen = ((numberOfBits + 7) >> 3);
|
||||
if (m_data == null)
|
||||
if (m_buf == null)
|
||||
{
|
||||
m_data = new byte[byteLen];
|
||||
m_buf = ArrayPool<byte>.Shared.Rent(byteLen);
|
||||
return;
|
||||
}
|
||||
if (m_data.Length < byteLen)
|
||||
Array.Resize<byte>(ref m_data, byteLen);
|
||||
return;
|
||||
|
||||
if (m_buf.Length < byteLen)
|
||||
{
|
||||
var pool = ArrayPool<byte>.Shared;
|
||||
var oldBuf = m_buf;
|
||||
m_buf = pool.Rent(byteLen);
|
||||
new Span<byte>(oldBuf).CopyTo(m_buf);
|
||||
pool.Return(oldBuf);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -134,12 +149,49 @@ namespace Lidgren.Network
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes all bytes in an array
|
||||
/// Writes a number of zeroed bytes
|
||||
/// </summary>
|
||||
public void Write(byte[] source)
|
||||
public void Zero(int length)
|
||||
{
|
||||
if (length < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(length), length, "Must be positive.");
|
||||
int bits = length * 8;
|
||||
EnsureBufferSize(m_bitLength + bits);
|
||||
NetBitWriter.Zero(bits, m_data, m_bitLength);
|
||||
m_bitLength += bits;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a stream out of a constrained region of the buffer for writing.
|
||||
/// </summary>
|
||||
/// <param name="byteLength">The length of the constrained region in bytes.</param>
|
||||
/// <returns>A writable constrained buffer region wrapped by a stream.</returns>
|
||||
public Stream WriteAsStream(int byteLength)
|
||||
{
|
||||
var bitLength = byteLength*8;
|
||||
EnsureBufferSize(m_bitLength + byteLength);
|
||||
var stream = new WriteOnlyWrapperStream(this, m_bitLength, bitLength);
|
||||
m_bitLength += bitLength;
|
||||
return stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a stream for appending to the end of the buffer.
|
||||
/// </summary>
|
||||
/// <returns>A writable stream that appends to the buffer.</returns>
|
||||
public Stream AppendViaStream()
|
||||
{
|
||||
return new AppenderStream(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes all bytes in an array.
|
||||
/// </summary>
|
||||
public void Write(ReadOnlySpan<byte> source)
|
||||
{
|
||||
if (source == null)
|
||||
throw new ArgumentNullException("source");
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
int bits = source.Length * 8;
|
||||
EnsureBufferSize(m_bitLength + bits);
|
||||
NetBitWriter.WriteBytes(source, 0, source.Length, m_data, m_bitLength);
|
||||
@@ -149,10 +201,10 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Writes the specified number of bytes from an array
|
||||
/// </summary>
|
||||
public void Write(byte[] source, int offsetInBytes, int numberOfBytes)
|
||||
public void Write(Span<byte> source, int offsetInBytes, int numberOfBytes)
|
||||
{
|
||||
if (source == null)
|
||||
throw new ArgumentNullException("source");
|
||||
throw new ArgumentNullException(nameof(source));
|
||||
int bits = numberOfBytes * 8;
|
||||
EnsureBufferSize(m_bitLength + bits);
|
||||
NetBitWriter.WriteBytes(source, offsetInBytes, numberOfBytes, m_data, m_bitLength);
|
||||
@@ -216,39 +268,24 @@ namespace Lidgren.Network
|
||||
m_bitLength = newBitLength;
|
||||
}
|
||||
|
||||
#if UNSAFE
|
||||
/// <summary>
|
||||
/// Writes a 32 bit signed integer
|
||||
/// </summary>
|
||||
public unsafe void Write(Int32 source)
|
||||
{
|
||||
EnsureBufferSize(m_bitLength + 32);
|
||||
|
||||
// can write fast?
|
||||
if (m_bitLength % 8 == 0)
|
||||
{
|
||||
fixed (byte* numRef = &Data[m_bitLength / 8])
|
||||
{
|
||||
*((int*)numRef) = source;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NetBitWriter.WriteUInt32((UInt32)source, 32, Data, m_bitLength);
|
||||
}
|
||||
m_bitLength += 32;
|
||||
}
|
||||
#else
|
||||
/// <summary>
|
||||
/// Writes a 32 bit signed integer
|
||||
/// </summary>
|
||||
public void Write(Int32 source)
|
||||
{
|
||||
EnsureBufferSize(m_bitLength + 32);
|
||||
NetBitWriter.WriteUInt32((UInt32)source, 32, m_data, m_bitLength);
|
||||
|
||||
// can write fast?
|
||||
if ((m_bitLength & 7) == 0)
|
||||
{
|
||||
MemoryMarshal.Write(new Span<byte>(Buffer, m_bitLength / 8, 4), ref source);
|
||||
}
|
||||
else
|
||||
{
|
||||
NetBitWriter.WriteUInt32((UInt32)source, 32, Buffer, m_bitLength);
|
||||
}
|
||||
m_bitLength += 32;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 32 bit signed integer at a given offset in the buffer
|
||||
@@ -261,41 +298,25 @@ namespace Lidgren.Network
|
||||
m_bitLength = newBitLength;
|
||||
}
|
||||
|
||||
#if UNSAFE
|
||||
/// <summary>
|
||||
/// Writes a 32 bit unsigned integer
|
||||
/// </summary>
|
||||
public unsafe void Write(UInt32 source)
|
||||
public void Write(UInt32 source)
|
||||
{
|
||||
EnsureBufferSize(m_bitLength + 32);
|
||||
|
||||
// can write fast?
|
||||
if (m_bitLength % 8 == 0)
|
||||
if ((m_bitLength & 7) == 0)
|
||||
{
|
||||
fixed (byte* numRef = &Data[m_bitLength / 8])
|
||||
{
|
||||
*((uint*)numRef) = source;
|
||||
}
|
||||
MemoryMarshal.Write(new Span<byte>(Buffer, m_bitLength / 8, 4), ref source);
|
||||
}
|
||||
else
|
||||
{
|
||||
NetBitWriter.WriteUInt32(source, 32, Data, m_bitLength);
|
||||
NetBitWriter.WriteUInt32(source, 32, Buffer, m_bitLength);
|
||||
}
|
||||
|
||||
m_bitLength += 32;
|
||||
}
|
||||
#else
|
||||
/// <summary>
|
||||
/// Writes a 32 bit unsigned integer
|
||||
/// </summary>
|
||||
[CLSCompliant(false)]
|
||||
public void Write(UInt32 source)
|
||||
{
|
||||
EnsureBufferSize(m_bitLength + 32);
|
||||
NetBitWriter.WriteUInt32(source, 32, m_data, m_bitLength);
|
||||
m_bitLength += 32;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 32 bit unsigned integer at a given offset in the buffer
|
||||
@@ -403,79 +424,33 @@ namespace Lidgren.Network
|
||||
//
|
||||
// Floating point
|
||||
//
|
||||
#if UNSAFE
|
||||
/// <summary>
|
||||
/// Writes a 32 bit floating point value
|
||||
/// </summary>
|
||||
public unsafe void Write(float source)
|
||||
{
|
||||
uint val = *((uint*)&source);
|
||||
#if BIGENDIAN
|
||||
val = NetUtility.SwapByteOrder(val);
|
||||
#endif
|
||||
Write(val);
|
||||
}
|
||||
#else
|
||||
/// <summary>
|
||||
/// Writes a 32 bit floating point value
|
||||
/// </summary>
|
||||
public void Write(float source)
|
||||
{
|
||||
// Use union to avoid BitConverter.GetBytes() which allocates memory on the heap
|
||||
SingleUIntUnion su;
|
||||
su.UIntValue = 0; // must initialize every member of the union to avoid warning
|
||||
su.SingleValue = source;
|
||||
|
||||
#if BIGENDIAN
|
||||
// swap byte order
|
||||
su.UIntValue = NetUtility.SwapByteOrder(su.UIntValue);
|
||||
#endif
|
||||
Write(su.UIntValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNSAFE
|
||||
/// <summary>
|
||||
/// Writes a 64 bit floating point value
|
||||
/// </summary>
|
||||
public unsafe void Write(double source)
|
||||
{
|
||||
ulong val = *((ulong*)&source);
|
||||
#if BIGENDIAN
|
||||
val = NetUtility.SwapByteOrder(val);
|
||||
#endif
|
||||
uint val = MemoryMarshal.Cast<float,uint>(MemoryMarshal.CreateReadOnlySpan(ref source, 1))[0];
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
val = BinaryPrimitives.ReverseEndianness(val);
|
||||
}
|
||||
Write(val);
|
||||
}
|
||||
#else
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 64 bit floating point value
|
||||
/// </summary>
|
||||
public void Write(double source)
|
||||
{
|
||||
byte[] val = BitConverter.GetBytes(source);
|
||||
#if BIGENDIAN
|
||||
// 0 1 2 3 4 5 6 7
|
||||
ulong val = MemoryMarshal.Cast<double,ulong>(MemoryMarshal.CreateReadOnlySpan(ref source, 1))[0];
|
||||
|
||||
// swap byte order
|
||||
byte tmp = val[7];
|
||||
val[7] = val[0];
|
||||
val[0] = tmp;
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
val = BinaryPrimitives.ReverseEndianness(val);
|
||||
}
|
||||
|
||||
tmp = val[6];
|
||||
val[6] = val[1];
|
||||
val[1] = tmp;
|
||||
|
||||
tmp = val[5];
|
||||
val[5] = val[2];
|
||||
val[2] = tmp;
|
||||
|
||||
tmp = val[4];
|
||||
val[4] = val[3];
|
||||
val[3] = tmp;
|
||||
#endif
|
||||
Write(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Variable bits
|
||||
@@ -624,7 +599,9 @@ namespace Lidgren.Network
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(source);
|
||||
// ReSharper disable once SuggestVarOrType_Elsewhere
|
||||
Span<byte> bytes = stackalloc byte[Encoding.UTF8.GetByteCount(source)];
|
||||
Encoding.UTF8.GetBytes(source, bytes);
|
||||
EnsureBufferSize(m_bitLength + 8 + (bytes.Length * 8));
|
||||
WriteVariableUInt32((uint)bytes.Length);
|
||||
Write(bytes);
|
||||
@@ -692,7 +669,7 @@ namespace Lidgren.Network
|
||||
Write(buffer.m_data, 0, buffer.LengthBytes);
|
||||
|
||||
// did we write excessive bits?
|
||||
int bitsInLastByte = (buffer.m_bitLength % 8);
|
||||
int bitsInLastByte = (buffer.m_bitLength & 7);
|
||||
if (bitsInLastByte != 0)
|
||||
{
|
||||
int excessBits = 8 - bitsInLastByte;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
@@ -14,17 +15,17 @@ namespace Lidgren.Network
|
||||
private static readonly Dictionary<Type, MethodInfo> s_readMethods;
|
||||
private static readonly Dictionary<Type, MethodInfo> s_writeMethods;
|
||||
|
||||
internal byte[] m_data;
|
||||
internal byte[] m_buf;
|
||||
internal Span<byte> m_data => m_buf;
|
||||
internal int m_bitLength;
|
||||
internal int m_readPosition;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the internal data buffer
|
||||
/// </summary>
|
||||
public byte[] Data
|
||||
public byte[] Buffer
|
||||
{
|
||||
get { return m_data; }
|
||||
set { m_data = value; }
|
||||
get { return m_buf; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -94,5 +95,6 @@ namespace Lidgren.Network
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
@@ -200,12 +201,12 @@ namespace Lidgren.Network
|
||||
{
|
||||
if (m_localHailMessage != null)
|
||||
{
|
||||
byte[] hi = m_localHailMessage.Data;
|
||||
var hi = m_localHailMessage.Buffer;
|
||||
if (hi != null && hi.Length >= m_localHailMessage.LengthBytes)
|
||||
{
|
||||
if (om.LengthBytes + m_localHailMessage.LengthBytes > m_peerConfiguration.m_maximumTransmissionUnit - 10)
|
||||
m_peer.ThrowOrLog("Hail message too large; can maximally be " + (m_peerConfiguration.m_maximumTransmissionUnit - 10 - om.LengthBytes));
|
||||
om.Write(m_localHailMessage.Data, 0, m_localHailMessage.LengthBytes);
|
||||
om.Write(m_localHailMessage.Buffer, 0, m_localHailMessage.LengthBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,20 +284,19 @@ namespace Lidgren.Network
|
||||
{
|
||||
m_peer.VerifyNetworkThread();
|
||||
|
||||
byte[] hail;
|
||||
switch (tp)
|
||||
{
|
||||
case NetMessageType.Connect:
|
||||
if (m_status == NetConnectionStatus.ReceivedInitiation)
|
||||
{
|
||||
// Whee! Server full has already been checked
|
||||
bool ok = ValidateHandshakeData(ptr, payloadLength, out hail);
|
||||
bool ok = ValidateHandshakeData(ptr, payloadLength, out var hail);
|
||||
if (ok)
|
||||
{
|
||||
if (hail != null)
|
||||
{
|
||||
m_remoteHailMessage = m_peer.CreateIncomingMessage(NetIncomingMessageType.Data, hail);
|
||||
m_remoteHailMessage.LengthBits = (hail.Length * 8);
|
||||
m_remoteHailMessage.LengthBits = (hail.Count * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -402,18 +402,17 @@ namespace Lidgren.Network
|
||||
|
||||
private void HandleConnectResponse(double now, NetMessageType tp, int ptr, int payloadLength)
|
||||
{
|
||||
byte[] hail;
|
||||
switch (m_status)
|
||||
{
|
||||
case NetConnectionStatus.InitiatedConnect:
|
||||
// awesome
|
||||
bool ok = ValidateHandshakeData(ptr, payloadLength, out hail);
|
||||
bool ok = ValidateHandshakeData(ptr, payloadLength, out var hail);
|
||||
if (ok)
|
||||
{
|
||||
if (hail != null)
|
||||
{
|
||||
m_remoteHailMessage = m_peer.CreateIncomingMessage(NetIncomingMessageType.Data, hail);
|
||||
m_remoteHailMessage.LengthBits = (hail.Length * 8);
|
||||
m_remoteHailMessage.LengthBits = (hail.Count * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -441,7 +440,7 @@ namespace Lidgren.Network
|
||||
}
|
||||
}
|
||||
|
||||
private bool ValidateHandshakeData(int ptr, int payloadLength, out byte[] hail)
|
||||
private bool ValidateHandshakeData(int ptr, int payloadLength, out ArraySegment<byte> hail)
|
||||
{
|
||||
hail = null;
|
||||
|
||||
@@ -455,7 +454,7 @@ namespace Lidgren.Network
|
||||
|
||||
int remainingBytes = payloadLength - (msg.PositionInBytes - ptr);
|
||||
if (remainingBytes > 0)
|
||||
hail = msg.ReadBytes(remainingBytes);
|
||||
msg.ReadBytes(hail = new ArraySegment<byte>(ArrayPool<byte>.Shared.Rent(remainingBytes),0, remainingBytes));
|
||||
|
||||
if (remoteAppIdentifier != m_peer.m_configuration.AppIdentifier)
|
||||
{
|
||||
|
||||
@@ -104,8 +104,7 @@ namespace Lidgren.Network
|
||||
private void SendExpandMTU(double now, int size)
|
||||
{
|
||||
NetOutgoingMessage om = m_peer.CreateMessage(size);
|
||||
byte[] tmp = new byte[size];
|
||||
om.Write(tmp);
|
||||
om.Zero(size);
|
||||
om.m_messageType = NetMessageType.ExpandMTURequest;
|
||||
int len = om.Encode(m_peer.m_sendBuffer, 0, 0);
|
||||
|
||||
|
||||
@@ -76,45 +76,113 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Gets the number of sent packets for this connection
|
||||
/// </summary>
|
||||
public long SentPackets { get { return m_sentPackets; } }
|
||||
public long SentPackets => m_sentPackets;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of received packets for this connection
|
||||
/// </summary>
|
||||
public long ReceivedPackets { get { return m_receivedPackets; } }
|
||||
public long ReceivedPackets => m_receivedPackets;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of sent bytes for this connection
|
||||
/// </summary>
|
||||
public long SentBytes { get { return m_sentBytes; } }
|
||||
public long SentBytes => m_sentBytes;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of received bytes for this connection
|
||||
/// </summary>
|
||||
public long ReceivedBytes { get { return m_receivedBytes; } }
|
||||
public long ReceivedBytes => m_receivedBytes;
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Gets the number of sent messages for this connection
|
||||
/// </summary>
|
||||
public long SentMessages { get { return m_sentMessages; } }
|
||||
public long SentMessages => m_sentMessages;
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Gets the number of received messages for this connection
|
||||
/// </summary>
|
||||
public long ReceivedMessages { get { return m_receivedMessages; } }
|
||||
public long ReceivedMessages => m_receivedMessages;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of resent reliable messages for this connection
|
||||
/// </summary>
|
||||
public long ResentMessages { get { return m_resentMessagesDueToHole + m_resentMessagesDueToDelay; } }
|
||||
public long ResentMessages => m_resentMessagesDueToHole + m_resentMessagesDueToDelay;
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Gets the number of resent reliable messages for this connection due to holes
|
||||
/// </summary>
|
||||
public long ResentMessagesDueToHoles => m_resentMessagesDueToHole;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of resent reliable messages for this connection due to delays
|
||||
/// </summary>
|
||||
public long ResentMessagesDueToDelays => m_resentMessagesDueToDelay;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of dropped messages for this connection
|
||||
/// </summary>
|
||||
public long DroppedMessages { get { return m_droppedMessages; } }
|
||||
public long DroppedMessages => m_droppedMessages;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of dropped messages for this connection
|
||||
/// </summary>
|
||||
public long ReceivedFragments => m_receivedFragments;
|
||||
|
||||
// public double LastSendRespondedTo { get { return m_connection.m_lastSendRespondedTo; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of withheld messages for this connection
|
||||
/// </summary>
|
||||
private int WithheldMessages
|
||||
{
|
||||
get
|
||||
{
|
||||
int numWithheld = 0;
|
||||
foreach (NetReceiverChannelBase recChan in m_connection.m_receiveChannels)
|
||||
{
|
||||
var relRecChan = recChan as NetReliableOrderedReceiver;
|
||||
if (relRecChan == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < relRecChan.m_withheldMessages.Length; i++)
|
||||
if (relRecChan.m_withheldMessages[i] != null)
|
||||
numWithheld++;
|
||||
}
|
||||
|
||||
return numWithheld;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of unsent and stored messages for this connection
|
||||
/// </summary>
|
||||
private void GetUnsentAndStoredMessages(out int numUnsent, out int numStored)
|
||||
{
|
||||
numUnsent = 0;
|
||||
numStored = 0;
|
||||
foreach (NetSenderChannelBase sendChan in m_connection.m_sendChannels)
|
||||
{
|
||||
if (sendChan == null)
|
||||
continue;
|
||||
|
||||
numUnsent += sendChan.QueuedSendsCount;
|
||||
|
||||
var relSendChan = sendChan as NetReliableSenderChannel;
|
||||
if (relSendChan == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < relSendChan.m_storedMessages.Length; i++)
|
||||
if (relSendChan.m_storedMessages[i].Message != null)
|
||||
numStored++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if !USE_RELEASE_STATISTICS
|
||||
[Conditional("DEBUG")]
|
||||
#endif
|
||||
@@ -157,57 +225,26 @@ namespace Lidgren.Network
|
||||
m_droppedMessages++;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string that represents this object
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder bdr = new StringBuilder();
|
||||
//bdr.AppendLine("Average roundtrip time: " + NetTime.ToReadable(m_connection.m_averageRoundtripTime));
|
||||
bdr.AppendLine("Current MTU: " + m_connection.m_currentMTU);
|
||||
bdr.AppendLine("Sent " + m_sentBytes + " bytes in " + m_sentMessages + " messages in " + m_sentPackets + " packets");
|
||||
bdr.AppendLine("Received " + m_receivedBytes + " bytes in " + m_receivedMessages + " messages (of which " + m_receivedFragments + " fragments) in " + m_receivedPackets + " packets");
|
||||
bdr.AppendLine("Dropped " + m_droppedMessages + " messages (dupes/late/early)");
|
||||
GetUnsentAndStoredMessages(out var numUnsent, out var numStored);
|
||||
|
||||
if (m_resentMessagesDueToDelay > 0)
|
||||
bdr.AppendLine("Resent messages (delay): " + m_resentMessagesDueToDelay);
|
||||
if (m_resentMessagesDueToHole > 0)
|
||||
bdr.AppendLine("Resent messages (holes): " + m_resentMessagesDueToHole);
|
||||
var numWithheld = WithheldMessages;
|
||||
|
||||
int numUnsent = 0;
|
||||
int numStored = 0;
|
||||
foreach (NetSenderChannelBase sendChan in m_connection.m_sendChannels)
|
||||
{
|
||||
if (sendChan == null)
|
||||
continue;
|
||||
numUnsent += sendChan.QueuedSendsCount;
|
||||
|
||||
var relSendChan = sendChan as NetReliableSenderChannel;
|
||||
if (relSendChan != null)
|
||||
{
|
||||
for (int i = 0; i < relSendChan.m_storedMessages.Length; i++)
|
||||
if (relSendChan.m_storedMessages[i].Message != null)
|
||||
numStored++;
|
||||
}
|
||||
}
|
||||
|
||||
int numWithheld = 0;
|
||||
foreach (NetReceiverChannelBase recChan in m_connection.m_receiveChannels)
|
||||
{
|
||||
var relRecChan = recChan as NetReliableOrderedReceiver;
|
||||
if (relRecChan != null)
|
||||
{
|
||||
for (int i = 0; i < relRecChan.m_withheldMessages.Length; i++)
|
||||
if (relRecChan.m_withheldMessages[i] != null)
|
||||
numWithheld++;
|
||||
}
|
||||
}
|
||||
|
||||
bdr.AppendLine("Unsent messages: " + numUnsent);
|
||||
bdr.AppendLine("Stored messages: " + numStored);
|
||||
bdr.AppendLine("Withheld messages: " + numWithheld);
|
||||
|
||||
return bdr.ToString();
|
||||
return @$"Current MTU: {m_connection.m_currentMTU}
|
||||
Sent {m_sentBytes} bytes in {m_sentMessages} messages in {m_sentPackets} packets
|
||||
Received {m_receivedBytes} bytes in {m_receivedMessages} messages (of which {m_receivedFragments} fragments) in {m_receivedPackets} packets
|
||||
Dropped {m_droppedMessages} messages (dupes/late/early)
|
||||
Resent messages (delay): {m_resentMessagesDueToDelay}
|
||||
Resent messages (holes): {m_resentMessagesDueToHole}
|
||||
Unsent messages: {numUnsent}
|
||||
Stored messages: {numStored}
|
||||
Withheld messages: {numWithheld}";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace Lidgren.Network
|
||||
internal static class NetFragmentationHelper
|
||||
{
|
||||
internal static int WriteHeader(
|
||||
byte[] destination,
|
||||
Span<byte> destination,
|
||||
int ptr,
|
||||
int group,
|
||||
int totalBits,
|
||||
@@ -50,7 +50,7 @@ namespace Lidgren.Network
|
||||
return ptr;
|
||||
}
|
||||
|
||||
internal static int ReadHeader(byte[] buffer, int ptr, out int group, out int totalBits, out int chunkByteSize, out int chunkNumber)
|
||||
internal static int ReadHeader(Span<byte> buffer, int ptr, out int group, out int totalBits, out int chunkByteSize, out int chunkNumber)
|
||||
{
|
||||
int num1 = 0;
|
||||
int num2 = 0;
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace Lidgren.Network
|
||||
m_fragmentGroup = 0;
|
||||
}
|
||||
|
||||
internal int Encode(byte[] intoBuffer, int ptr, int sequenceNumber)
|
||||
internal int Encode(Span<byte> intoBuffer, int ptr, int sequenceNumber)
|
||||
{
|
||||
// 8 bits - NetMessageType
|
||||
// 1 bit - Fragment?
|
||||
@@ -78,7 +78,9 @@ namespace Lidgren.Network
|
||||
int byteLen = NetUtility.BytesToHoldBits(m_bitLength);
|
||||
if (byteLen > 0)
|
||||
{
|
||||
Buffer.BlockCopy(m_data, 0, intoBuffer, ptr, byteLen);
|
||||
m_data.Slice(0,byteLen)
|
||||
.CopyTo(intoBuffer.Slice(ptr,byteLen));
|
||||
//Buffer.BlockCopy(m_data, 0, intoBuffer, ptr, byteLen);
|
||||
ptr += byteLen;
|
||||
}
|
||||
}
|
||||
@@ -102,7 +104,9 @@ namespace Lidgren.Network
|
||||
int byteLen = NetUtility.BytesToHoldBits(m_bitLength);
|
||||
if (byteLen > 0)
|
||||
{
|
||||
Buffer.BlockCopy(m_data, (int)(m_fragmentChunkNumber * m_fragmentChunkByteSize), intoBuffer, ptr, byteLen);
|
||||
m_data.Slice(m_fragmentChunkNumber * m_fragmentChunkByteSize,byteLen)
|
||||
.CopyTo(intoBuffer.Slice(ptr, byteLen));
|
||||
//Buffer.BlockCopy(m_data, (int)(m_fragmentChunkNumber * m_fragmentChunkByteSize), intoBuffer, ptr, byteLen);
|
||||
ptr += byteLen;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -53,7 +54,7 @@ namespace Lidgren.Network
|
||||
NetOutgoingMessage chunk = CreateMessage(0);
|
||||
|
||||
chunk.m_bitLength = (bitsLeft > bitsPerChunk ? bitsPerChunk : bitsLeft);
|
||||
chunk.m_data = msg.m_data;
|
||||
chunk.m_buf = msg.m_buf;
|
||||
chunk.m_fragmentGroup = group;
|
||||
chunk.m_fragmentGroupTotalBits = totalBytes * 8;
|
||||
chunk.m_fragmentChunkByteSize = bytesPerChunk;
|
||||
@@ -127,9 +128,11 @@ namespace Lidgren.Network
|
||||
ReceivedFragmentGroup info;
|
||||
if (!groups.TryGetValue(group, out info))
|
||||
{
|
||||
info = new ReceivedFragmentGroup();
|
||||
info.Data = new byte[totalBytes];
|
||||
info.ReceivedChunks = new NetBitVector(totalNumChunks);
|
||||
info = new ReceivedFragmentGroup
|
||||
{
|
||||
Data = ArrayPool<byte>.Shared.Rent(totalBytes),
|
||||
ReceivedChunks = new NetBitVector(totalNumChunks)
|
||||
};
|
||||
groups[group] = info;
|
||||
}
|
||||
|
||||
@@ -138,7 +141,9 @@ namespace Lidgren.Network
|
||||
|
||||
// copy to data
|
||||
int offset = (chunkNumber * chunkByteSize);
|
||||
Buffer.BlockCopy(im.m_data, ptr, info.Data, offset, im.LengthBytes - ptr);
|
||||
//Buffer.BlockCopy(im.m_data, ptr, info.Data, offset, im.LengthBytes - ptr);
|
||||
im.m_data.Slice(ptr,im.LengthBytes - ptr)
|
||||
.CopyTo(new Span<byte>(info.Data,offset,im.LengthBytes - ptr));
|
||||
|
||||
int cnt = info.ReceivedChunks.Count();
|
||||
//LogVerbose("Found fragment #" + chunkNumber + " in group " + group + " offset " + offset + " of total bits " + totalBits + " (total chunks done " + cnt + ")");
|
||||
@@ -148,7 +153,7 @@ namespace Lidgren.Network
|
||||
if (info.ReceivedChunks.Count() == totalNumChunks)
|
||||
{
|
||||
// Done! Transform this incoming message
|
||||
im.m_data = info.Data;
|
||||
im.m_buf = info.Data;
|
||||
im.m_bitLength = (int)totalBits;
|
||||
im.m_isFragment = false;
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Diagnostics;
|
||||
using System.Security.Cryptography;
|
||||
using System.Net.Sockets;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
#if !__NOIPENDPOINT__
|
||||
using NetEndPoint = System.Net.IPEndPoint;
|
||||
#endif
|
||||
@@ -152,7 +153,7 @@ namespace Lidgren.Network
|
||||
const uint IOC_IN = 0x80000000;
|
||||
const uint IOC_VENDOR = 0x18000000;
|
||||
uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
|
||||
m_socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
|
||||
m_socket.IOControl((int)SIO_UDP_CONNRESET, new[] { Convert.ToByte(false) }, null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -191,19 +192,25 @@ namespace Lidgren.Network
|
||||
// bind to socket
|
||||
BindSocket(false);
|
||||
|
||||
m_receiveBuffer = new byte[m_configuration.ReceiveBufferSize];
|
||||
m_sendBuffer = new byte[m_configuration.SendBufferSize];
|
||||
m_readHelperMessage = new NetIncomingMessage(NetIncomingMessageType.Error);
|
||||
m_readHelperMessage.m_data = m_receiveBuffer;
|
||||
m_receiveBuffer = ArrayPool<byte>.Shared.Rent(m_configuration.ReceiveBufferSize);
|
||||
m_sendBuffer = ArrayPool<byte>.Shared.Rent(m_configuration.SendBufferSize);
|
||||
m_readHelperMessage = new NetIncomingMessage(NetIncomingMessageType.Error)
|
||||
{
|
||||
m_buf = m_receiveBuffer
|
||||
};
|
||||
|
||||
byte[] macBytes = NetUtility.GetMacAddressBytes();
|
||||
var macBytes = NetUtility.GetMacAddressBytes();
|
||||
|
||||
var boundEp = m_socket.LocalEndPoint as NetEndPoint;
|
||||
byte[] epBytes = BitConverter.GetBytes(boundEp.GetHashCode());
|
||||
byte[] combined = new byte[epBytes.Length + macBytes.Length];
|
||||
Array.Copy(epBytes, 0, combined, 0, epBytes.Length);
|
||||
Array.Copy(macBytes, 0, combined, epBytes.Length, macBytes.Length);
|
||||
m_uniqueIdentifier = BitConverter.ToInt64(NetUtility.ComputeSHAHash(combined), 0);
|
||||
var hashCode = boundEp!.GetHashCode();
|
||||
var epBytes = MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref hashCode,1));
|
||||
// ReSharper disable once SuggestVarOrType_Elsewhere
|
||||
Span<byte> combined = stackalloc byte[epBytes.Length + macBytes.Length];
|
||||
//Array.Copy(epBytes, 0, combined, 0, epBytes.Length);
|
||||
epBytes.CopyTo(combined.Slice(0,epBytes.Length));
|
||||
//Array.Copy(macBytes, 0, combined, epBytes.Length, macBytes.Length);
|
||||
macBytes.CopyTo(combined.Slice(epBytes.Length, macBytes.Length));
|
||||
m_uniqueIdentifier = MemoryMarshal.Cast<byte,long>(NetUtility.ComputeSHAHash(combined, stackalloc byte[32]))[0];
|
||||
|
||||
m_status = NetPeerStatus.Running;
|
||||
}
|
||||
@@ -556,7 +563,9 @@ namespace Lidgren.Network
|
||||
msg.m_senderEndPoint = ipsender;
|
||||
msg.m_bitLength = payloadBitLength;
|
||||
|
||||
Buffer.BlockCopy(m_receiveBuffer, ptr, msg.m_data, 0, payloadByteLength);
|
||||
//Buffer.BlockCopy(m_receiveBuffer, ptr, msg.m_data, 0, payloadByteLength);
|
||||
new Memory<byte>(m_receiveBuffer,ptr,payloadByteLength).Span
|
||||
.CopyTo(msg.m_data.Slice(0, payloadByteLength));
|
||||
if (sender != null)
|
||||
{
|
||||
if (tp == NetMessageType.Unconnected)
|
||||
@@ -606,7 +615,12 @@ namespace Lidgren.Network
|
||||
{
|
||||
NetIncomingMessage dm = CreateIncomingMessage(NetIncomingMessageType.DiscoveryRequest, payloadByteLength);
|
||||
if (payloadByteLength > 0)
|
||||
Buffer.BlockCopy(m_receiveBuffer, ptr, dm.m_data, 0, payloadByteLength);
|
||||
{
|
||||
//Buffer.BlockCopy(m_receiveBuffer, ptr, dm.m_data, 0, payloadByteLength);
|
||||
new Memory<byte>(m_receiveBuffer, ptr, payloadByteLength).Span
|
||||
.CopyTo(dm.m_data.Slice(0, payloadByteLength));
|
||||
}
|
||||
|
||||
dm.m_receiveTime = now;
|
||||
dm.m_bitLength = payloadByteLength * 8;
|
||||
dm.m_senderEndPoint = senderEndPoint;
|
||||
@@ -620,7 +634,11 @@ namespace Lidgren.Network
|
||||
{
|
||||
NetIncomingMessage dr = CreateIncomingMessage(NetIncomingMessageType.DiscoveryResponse, payloadByteLength);
|
||||
if (payloadByteLength > 0)
|
||||
Buffer.BlockCopy(m_receiveBuffer, ptr, dr.m_data, 0, payloadByteLength);
|
||||
{
|
||||
//Buffer.BlockCopy(m_receiveBuffer, ptr, dr.m_data, 0, payloadByteLength);
|
||||
new Memory<byte>(m_receiveBuffer, ptr, payloadByteLength).Span
|
||||
.CopyTo(dr.m_data.Slice(0, payloadByteLength));
|
||||
}
|
||||
dr.m_receiveTime = now;
|
||||
dr.m_bitLength = payloadByteLength * 8;
|
||||
dr.m_senderEndPoint = senderEndPoint;
|
||||
|
||||
@@ -20,6 +20,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//#define USE_RELEASE_STATISTICS
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
@@ -89,8 +90,10 @@ namespace Lidgren.Network
|
||||
// Enqueue delayed packet
|
||||
DelayedPacket p = new DelayedPacket();
|
||||
p.Target = target;
|
||||
p.Data = new byte[numBytes];
|
||||
Buffer.BlockCopy(m_sendBuffer, 0, p.Data, 0, numBytes);
|
||||
p.Data = ArrayPool<byte>.Shared.Rent(numBytes);
|
||||
//Buffer.BlockCopy(m_sendBuffer, 0, p.Data, 0, numBytes);
|
||||
new Memory<byte>(m_sendBuffer, 0, numBytes)
|
||||
.CopyTo(p.Data);
|
||||
p.DelayedUntil = NetTime.Now + delay;
|
||||
|
||||
m_delayedPackets.Add(p);
|
||||
@@ -113,8 +116,9 @@ namespace Lidgren.Network
|
||||
{
|
||||
if (now > p.DelayedUntil)
|
||||
{
|
||||
ActuallySendPacket(p.Data, p.Data.Length, p.Target, out connectionReset);
|
||||
ActuallySendPacket(new Span<byte>(p.Data), p.Data.Length, p.Target, out connectionReset);
|
||||
m_delayedPackets.Remove(p);
|
||||
ArrayPool<byte>.Shared.Return(p.Data);
|
||||
goto RestartDelaySending;
|
||||
}
|
||||
}
|
||||
@@ -126,7 +130,10 @@ namespace Lidgren.Network
|
||||
{
|
||||
bool connectionReset;
|
||||
foreach (DelayedPacket p in m_delayedPackets)
|
||||
ActuallySendPacket(p.Data, p.Data.Length, p.Target, out connectionReset);
|
||||
{
|
||||
ActuallySendPacket(new Span<byte>(p.Data), p.Data.Length, p.Target, out connectionReset);
|
||||
ArrayPool<byte>.Shared.Return(p.Data);
|
||||
}
|
||||
m_delayedPackets.Clear();
|
||||
}
|
||||
catch { }
|
||||
@@ -135,7 +142,7 @@ namespace Lidgren.Network
|
||||
//Avoids allocation on mapping to IPv6
|
||||
private IPEndPoint targetCopy = new IPEndPoint(IPAddress.Any, 0);
|
||||
|
||||
internal bool ActuallySendPacket(byte[] data, int numBytes, NetEndPoint target, out bool connectionReset)
|
||||
internal bool ActuallySendPacket(ReadOnlySpan<byte> data, int numBytes, NetEndPoint target, out bool connectionReset)
|
||||
{
|
||||
connectionReset = false;
|
||||
IPAddress ba = default(IPAddress);
|
||||
@@ -161,7 +168,7 @@ namespace Lidgren.Network
|
||||
targetCopy.Address = target.Address;
|
||||
}
|
||||
|
||||
int bytesSent = m_socket.SendTo(data, 0, numBytes, SocketFlags.None, targetCopy);
|
||||
int bytesSent = m_socket.SendTo(data.Slice( 0, numBytes ), 0, targetCopy);
|
||||
if (numBytes != bytesSent)
|
||||
LogWarning("Failed to send the full " + numBytes + "; only " + bytesSent + " bytes sent in packet!");
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
@@ -6,27 +7,21 @@ namespace Lidgren.Network
|
||||
{
|
||||
public partial class NetPeer
|
||||
{
|
||||
internal List<byte[]> m_storagePool;
|
||||
private NetQueue<NetOutgoingMessage> m_outgoingMessagesPool;
|
||||
private NetQueue<NetIncomingMessage> m_incomingMessagesPool;
|
||||
|
||||
internal int m_storagePoolBytes;
|
||||
internal int m_storageSlotsUsedCount;
|
||||
private int m_maxCacheCount;
|
||||
|
||||
private void InitializePools()
|
||||
{
|
||||
m_storageSlotsUsedCount = 0;
|
||||
|
||||
if (m_configuration.UseMessageRecycling)
|
||||
{
|
||||
m_storagePool = new List<byte[]>(16);
|
||||
m_outgoingMessagesPool = new NetQueue<NetOutgoingMessage>(4);
|
||||
m_incomingMessagesPool = new NetQueue<NetIncomingMessage>(4);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_storagePool = null;
|
||||
m_outgoingMessagesPool = null;
|
||||
m_incomingMessagesPool = null;
|
||||
}
|
||||
@@ -36,63 +31,12 @@ namespace Lidgren.Network
|
||||
|
||||
internal byte[] GetStorage(int minimumCapacityInBytes)
|
||||
{
|
||||
if (m_storagePool == null)
|
||||
return new byte[minimumCapacityInBytes];
|
||||
|
||||
lock (m_storagePool)
|
||||
{
|
||||
for (int i = 0; i < m_storagePool.Count; i++)
|
||||
{
|
||||
byte[] retval = m_storagePool[i];
|
||||
if (retval != null && retval.Length >= minimumCapacityInBytes)
|
||||
{
|
||||
m_storagePool[i] = null;
|
||||
m_storageSlotsUsedCount--;
|
||||
m_storagePoolBytes -= retval.Length;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_statistics.m_bytesAllocated += minimumCapacityInBytes;
|
||||
return new byte[minimumCapacityInBytes];
|
||||
return ArrayPool<byte>.Shared.Rent(minimumCapacityInBytes);
|
||||
}
|
||||
|
||||
internal void Recycle(byte[] storage)
|
||||
{
|
||||
if (m_storagePool == null || storage == null)
|
||||
return;
|
||||
|
||||
lock (m_storagePool)
|
||||
{
|
||||
int cnt = m_storagePool.Count;
|
||||
for (int i = 0; i < cnt; i++)
|
||||
{
|
||||
if (m_storagePool[i] == null)
|
||||
{
|
||||
m_storageSlotsUsedCount++;
|
||||
m_storagePoolBytes += storage.Length;
|
||||
m_storagePool[i] = storage;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_storagePool.Count >= m_maxCacheCount)
|
||||
{
|
||||
// pool is full; replace randomly chosen entry to keep size distribution
|
||||
var idx = NetRandom.Instance.Next(m_storagePool.Count);
|
||||
|
||||
m_storagePoolBytes -= m_storagePool[idx].Length;
|
||||
m_storagePoolBytes += storage.Length;
|
||||
|
||||
m_storagePool[idx] = storage; // replace
|
||||
}
|
||||
else
|
||||
{
|
||||
m_storageSlotsUsedCount++;
|
||||
m_storagePoolBytes += storage.Length;
|
||||
m_storagePool.Add(storage);
|
||||
}
|
||||
}
|
||||
ArrayPool<byte>.Shared.Return(storage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -137,19 +81,19 @@ namespace Lidgren.Network
|
||||
NetException.Assert(retval.m_recyclingCount == 0, "Wrong recycling count! Should be zero" + retval.m_recyclingCount);
|
||||
|
||||
if (initialCapacity > 0)
|
||||
retval.m_data = GetStorage(initialCapacity);
|
||||
retval.m_buf = GetStorage(initialCapacity);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
internal NetIncomingMessage CreateIncomingMessage(NetIncomingMessageType tp, byte[] useStorageData)
|
||||
internal NetIncomingMessage CreateIncomingMessage(NetIncomingMessageType tp, ArraySegment<byte> useStorageData)
|
||||
{
|
||||
NetIncomingMessage retval;
|
||||
if (m_incomingMessagesPool == null || !m_incomingMessagesPool.TryDequeue(out retval))
|
||||
retval = new NetIncomingMessage(tp);
|
||||
else
|
||||
retval.m_incomingMessageType = tp;
|
||||
retval.m_data = useStorageData;
|
||||
retval.m_buf = useStorageData.Array;
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -160,7 +104,7 @@ namespace Lidgren.Network
|
||||
retval = new NetIncomingMessage(tp);
|
||||
else
|
||||
retval.m_incomingMessageType = tp;
|
||||
retval.m_data = GetStorage(minimumByteSize);
|
||||
retval.m_buf = GetStorage(minimumByteSize);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -174,8 +118,8 @@ namespace Lidgren.Network
|
||||
|
||||
NetException.Assert(m_incomingMessagesPool.Contains(msg) == false, "Recyling already recycled incoming message! Thread race?");
|
||||
|
||||
byte[] storage = msg.m_data;
|
||||
msg.m_data = null;
|
||||
byte[] storage = msg.m_buf;
|
||||
msg.m_buf = null;
|
||||
Recycle(storage);
|
||||
msg.Reset();
|
||||
|
||||
@@ -207,8 +151,8 @@ namespace Lidgren.Network
|
||||
// however, in RELEASE, we'll just have to accept this and move on with life
|
||||
msg.m_recyclingCount = 0;
|
||||
|
||||
byte[] storage = msg.m_data;
|
||||
msg.m_data = null;
|
||||
byte[] storage = msg.m_buf;
|
||||
msg.m_buf = null;
|
||||
|
||||
// message fragments cannot be recycled
|
||||
// TODO: find a way to recycle large message after all fragments has been acknowledged; or? possibly better just to garbage collect them
|
||||
|
||||
@@ -44,8 +44,6 @@ namespace Lidgren.Network
|
||||
internal int m_sentBytes;
|
||||
internal int m_receivedBytes;
|
||||
|
||||
internal long m_bytesAllocated;
|
||||
|
||||
internal NetPeerStatistics(NetPeer peer)
|
||||
{
|
||||
m_peer = peer;
|
||||
@@ -63,56 +61,42 @@ namespace Lidgren.Network
|
||||
|
||||
m_sentBytes = 0;
|
||||
m_receivedBytes = 0;
|
||||
|
||||
m_bytesAllocated = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of sent packets since the NetPeer was initialized
|
||||
/// </summary>
|
||||
public int SentPackets { get { return m_sentPackets; } }
|
||||
public int SentPackets => m_sentPackets;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of received packets since the NetPeer was initialized
|
||||
/// </summary>
|
||||
public int ReceivedPackets { get { return m_receivedPackets; } }
|
||||
public int ReceivedPackets => m_receivedPackets;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of sent messages since the NetPeer was initialized
|
||||
/// </summary>
|
||||
public int SentMessages { get { return m_sentMessages; } }
|
||||
public int SentMessages => m_sentMessages;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of received messages since the NetPeer was initialized
|
||||
/// </summary>
|
||||
public int ReceivedMessages { get { return m_receivedMessages; } }
|
||||
public int ReceivedMessages => m_receivedMessages;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of received fragments since the NetPeer was initialized
|
||||
/// </summary>
|
||||
public int ReceivedFragments => m_receivedFragments;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of sent bytes since the NetPeer was initialized
|
||||
/// </summary>
|
||||
public int SentBytes { get { return m_sentBytes; } }
|
||||
public int SentBytes => m_sentBytes;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of received bytes since the NetPeer was initialized
|
||||
/// </summary>
|
||||
public int ReceivedBytes { get { return m_receivedBytes; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bytes allocated (and possibly garbage collected) for message storage
|
||||
/// </summary>
|
||||
public long StorageBytesAllocated { get { return m_bytesAllocated; } }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bytes in the recycled pool
|
||||
/// </summary>
|
||||
public int BytesInRecyclePool
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (m_peer.m_storagePool)
|
||||
return m_peer.m_storagePoolBytes;
|
||||
}
|
||||
}
|
||||
public int ReceivedBytes => m_receivedBytes;
|
||||
|
||||
#if !USE_RELEASE_STATISTICS
|
||||
[Conditional("DEBUG")]
|
||||
@@ -140,19 +124,15 @@ namespace Lidgren.Network
|
||||
/// </summary>
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder bdr = new StringBuilder();
|
||||
bdr.AppendLine(m_peer.ConnectionsCount.ToString() + " connections");
|
||||
#if DEBUG || USE_RELEASE_STATISTICS
|
||||
bdr.AppendLine("Sent " + m_sentBytes + " bytes in " + m_sentMessages + " messages in " + m_sentPackets + " packets");
|
||||
bdr.AppendLine("Received " + m_receivedBytes + " bytes in " + m_receivedMessages + " messages (of which " + m_receivedFragments + " fragments) in " + m_receivedPackets + " packets");
|
||||
return @$"{m_peer.ConnectionsCount} connections
|
||||
Sent {m_sentBytes} bytes in {m_sentMessages} messages in {m_sentPackets} packets
|
||||
Received {m_receivedBytes} bytes in {m_receivedMessages} messages (of which {m_receivedFragments} fragments) in {m_receivedPackets} packets";
|
||||
#else
|
||||
bdr.AppendLine("Sent (n/a) bytes in (n/a) messages in (n/a) packets");
|
||||
bdr.AppendLine("Received (n/a) bytes in (n/a) messages in (n/a) packets");
|
||||
return @$"{m_peer.ConnectionsCount} connections
|
||||
Sent (n/a) bytes in (n/a) messages in (n/a) packets
|
||||
Received (n/a) bytes in (n/a) messages in (n/a) packets";
|
||||
#endif
|
||||
bdr.AppendLine("Storage allocated " + m_bytesAllocated + " bytes");
|
||||
if (m_peer.m_storagePool != null)
|
||||
bdr.AppendLine("Recycled pool " + m_peer.m_storagePoolBytes + " bytes (" + m_peer.m_storageSlotsUsedCount + " entries)");
|
||||
return bdr.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,9 @@ namespace Lidgren.Network
|
||||
string two = NetUtility.ToHexString(g.ToByteArrayUnsigned());
|
||||
|
||||
string ccstr = one + two.PadLeft(one.Length, '0');
|
||||
byte[] cc = NetUtility.ToByteArray(ccstr);
|
||||
var cc = NetUtility.HexToBytes(ccstr, stackalloc byte[ccstr.Length*2]);
|
||||
|
||||
var ccHashed = NetUtility.ComputeSHAHash(cc);
|
||||
var ccHashed = NetUtility.ComputeSHAHash(cc, stackalloc byte[NetUtility.SHAHashSize]);
|
||||
return new NetBigInteger(NetUtility.ToHexString(ccHashed), 16);
|
||||
}
|
||||
|
||||
@@ -53,23 +53,29 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Computer private key (x)
|
||||
/// </summary>
|
||||
public static byte[] ComputePrivateKey(string username, string password, byte[] salt)
|
||||
public static byte[] ComputePrivateKey(string username, string password, ReadOnlySpan<byte> salt)
|
||||
{
|
||||
byte[] tmp = Encoding.UTF8.GetBytes(username + ":" + password);
|
||||
byte[] innerHash = NetUtility.ComputeSHAHash(tmp);
|
||||
var tmpStr = username + ":" + password;
|
||||
// ReSharper disable once SuggestVarOrType_Elsewhere
|
||||
Span<byte> tmp = stackalloc byte[Encoding.UTF8.GetByteCount(tmpStr)];
|
||||
Encoding.UTF8.GetBytes(tmpStr, tmp);
|
||||
var innerHash = NetUtility.ComputeSHAHash(tmp, stackalloc byte[32]);
|
||||
|
||||
byte[] total = new byte[innerHash.Length + salt.Length];
|
||||
Buffer.BlockCopy(salt, 0, total, 0, salt.Length);
|
||||
Buffer.BlockCopy(innerHash, 0, total, salt.Length, innerHash.Length);
|
||||
// ReSharper disable once SuggestVarOrType_Elsewhere
|
||||
Span<byte> total = stackalloc byte[innerHash.Length + salt.Length];
|
||||
//Buffer.BlockCopy(salt, 0, total, 0, salt.Length);
|
||||
salt.CopyTo(total);
|
||||
//Buffer.BlockCopy(innerHash, 0, total, salt.Length, innerHash.Length);
|
||||
innerHash.CopyTo(total.Slice(salt.Length, innerHash.Length));
|
||||
|
||||
// x ie. H(salt || H(username || ":" || password))
|
||||
return new NetBigInteger(NetUtility.ToHexString(NetUtility.ComputeSHAHash(total)), 16).ToByteArrayUnsigned();
|
||||
return new NetBigInteger(NetUtility.ToHexString(NetUtility.ComputeSHAHash(total, stackalloc byte[32])), 16).ToByteArrayUnsigned();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a verifier that the server can later use to authenticate users later on (v)
|
||||
/// </summary>
|
||||
public static byte[] ComputeServerVerifier(byte[] privateKey)
|
||||
public static byte[] ComputeServerVerifier(ReadOnlySpan<byte> privateKey)
|
||||
{
|
||||
NetBigInteger x = new NetBigInteger(NetUtility.ToHexString(privateKey), 16);
|
||||
|
||||
@@ -82,7 +88,7 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Compute client public ephemeral value (A)
|
||||
/// </summary>
|
||||
public static byte[] ComputeClientEphemeral(byte[] clientPrivateEphemeral) // a
|
||||
public static byte[] ComputeClientEphemeral(ReadOnlySpan<byte> clientPrivateEphemeral) // a
|
||||
{
|
||||
// A= g^a (mod N)
|
||||
NetBigInteger a = new NetBigInteger(NetUtility.ToHexString(clientPrivateEphemeral), 16);
|
||||
@@ -94,7 +100,7 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Compute server ephemeral value (B)
|
||||
/// </summary>
|
||||
public static byte[] ComputeServerEphemeral(byte[] serverPrivateEphemeral, byte[] verifier) // b
|
||||
public static byte[] ComputeServerEphemeral(ReadOnlySpan<byte> serverPrivateEphemeral, ReadOnlySpan<byte> verifier) // b
|
||||
{
|
||||
var b = new NetBigInteger(NetUtility.ToHexString(serverPrivateEphemeral), 16);
|
||||
var v = new NetBigInteger(NetUtility.ToHexString(verifier), 16);
|
||||
@@ -110,7 +116,7 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Compute intermediate value (u)
|
||||
/// </summary>
|
||||
public static byte[] ComputeU(byte[] clientPublicEphemeral, byte[] serverPublicEphemeral)
|
||||
public static byte[] ComputeU(ReadOnlySpan<byte> clientPublicEphemeral, ReadOnlySpan<byte> serverPublicEphemeral)
|
||||
{
|
||||
// u = SHA-1(A || B)
|
||||
string one = NetUtility.ToHexString(clientPublicEphemeral);
|
||||
@@ -119,9 +125,9 @@ namespace Lidgren.Network
|
||||
int len = 66; // Math.Max(one.Length, two.Length);
|
||||
string ccstr = one.PadLeft(len, '0') + two.PadLeft(len, '0');
|
||||
|
||||
byte[] cc = NetUtility.ToByteArray(ccstr);
|
||||
var cc = NetUtility.HexToBytes(ccstr, stackalloc byte[ccstr.Length*2]);
|
||||
|
||||
var ccHashed = NetUtility.ComputeSHAHash(cc);
|
||||
var ccHashed = NetUtility.ComputeSHAHash(cc, stackalloc byte[32]);
|
||||
|
||||
return new NetBigInteger(NetUtility.ToHexString(ccHashed), 16).ToByteArrayUnsigned();
|
||||
}
|
||||
@@ -129,7 +135,7 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Computes the server session value
|
||||
/// </summary>
|
||||
public static byte[] ComputeServerSessionValue(byte[] clientPublicEphemeral, byte[] verifier, byte[] udata, byte[] serverPrivateEphemeral)
|
||||
public static byte[] ComputeServerSessionValue(ReadOnlySpan<byte> clientPublicEphemeral, ReadOnlySpan<byte> verifier, ReadOnlySpan<byte> udata, ReadOnlySpan<byte> serverPrivateEphemeral)
|
||||
{
|
||||
// S = (Av^u) ^ b (mod N)
|
||||
var A = new NetBigInteger(NetUtility.ToHexString(clientPublicEphemeral), 16);
|
||||
@@ -161,9 +167,9 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Create XTEA symmetrical encryption object from sessionValue
|
||||
/// </summary>
|
||||
public static NetXtea CreateEncryption(NetPeer peer, byte[] sessionValue)
|
||||
public static NetXtea CreateEncryption(NetPeer peer, ReadOnlySpan<byte> sessionValue)
|
||||
{
|
||||
var hash = NetUtility.ComputeSHAHash(sessionValue);
|
||||
var hash = NetUtility.ComputeSHAHash(sessionValue, stackalloc byte[32]);
|
||||
|
||||
var key = new byte[16];
|
||||
for(int i=0;i<16;i++)
|
||||
|
||||
@@ -23,12 +23,14 @@ using NetAddress = System.Net.IPAddress;
|
||||
#endif
|
||||
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Net;
|
||||
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Lidgren.Network
|
||||
@@ -78,6 +80,13 @@ namespace Lidgren.Network
|
||||
}
|
||||
|
||||
private static IPAddress s_broadcastAddress;
|
||||
|
||||
#if NON_IEC_UNITS
|
||||
private static readonly string[] ByteStringSuffixes = { "B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
|
||||
#else
|
||||
private static readonly string[] ByteStringSuffixes = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB" };
|
||||
#endif
|
||||
|
||||
public static IPAddress GetCachedBroadcastAddress()
|
||||
{
|
||||
if (s_broadcastAddress == null)
|
||||
@@ -219,27 +228,62 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Create a hex string from an array of bytes
|
||||
/// </summary>
|
||||
public static string ToHexString(byte[] data)
|
||||
public static string ToHexString(ReadOnlySpan<byte> data, int offset, int length)
|
||||
{
|
||||
return ToHexString(data, 0, data.Length);
|
||||
return ToHexString(data.Slice(offset, length));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a hex string from an array of bytes
|
||||
/// </summary>
|
||||
public static string ToHexString(byte[] data, int offset, int length)
|
||||
#if UNSAFE
|
||||
public static unsafe string ToHexString(ReadOnlySpan<byte> data)
|
||||
{
|
||||
char[] c = new char[length * 2];
|
||||
byte b;
|
||||
for (int i = 0; i < length; ++i)
|
||||
var l = data.Length;
|
||||
fixed (void* p = data)
|
||||
{
|
||||
b = ((byte)(data[offset + i] >> 4));
|
||||
c[i * 2] = (char)(b > 9 ? b + 0x37 : b + 0x30);
|
||||
b = ((byte)(data[offset + i] & 0xF));
|
||||
c[i * 2 + 1] = (char)(b > 9 ? b + 0x37 : b + 0x30);
|
||||
return string.Create(data.Length * 2, (p: (IntPtr) p, l), (c, d) =>
|
||||
{
|
||||
var s = new ReadOnlySpan<byte>((void*) d.p, d.l);
|
||||
var u = MemoryMarshal.Cast<char,int>(c);
|
||||
for (var i = 0; i < l; ++i)
|
||||
{
|
||||
var b = s[i];
|
||||
var nibLo = b >> 4;
|
||||
var isDigLo = (nibLo - 10) >> 31;
|
||||
var chLo = 55 + nibLo + (isDigLo & -7);
|
||||
var nibHi = b & 0xF;
|
||||
var isDigHi = (nibHi - 10) >> 31;
|
||||
var chHi = 55 + nibHi + (isDigHi & -7);
|
||||
u[i] = (chHi << 16) | chLo;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
public static string ToHexString(ReadOnlySpan<byte> data)
|
||||
{
|
||||
var l = data.Length;
|
||||
// ReSharper disable once SuggestVarOrType_Elsewhere
|
||||
Span<char> c = stackalloc char[l*2];
|
||||
var u = MemoryMarshal.Cast<char,int>(c);
|
||||
|
||||
for (var i = 0; i < l; ++i)
|
||||
{
|
||||
var b = data[i];
|
||||
var nibLo = b >> 4;
|
||||
var isDigLo = (nibLo - 10) >> 31;
|
||||
var chLo = 55 + nibLo + (isDigLo & -7);
|
||||
var nibHi = b & 0xF;
|
||||
var isDigHi = (nibHi - 10) >> 31;
|
||||
var chHi = 55 + nibHi + (isDigHi & -7);
|
||||
u[i] = (chHi << 16) | chLo;
|
||||
}
|
||||
|
||||
return new string(c);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the endpoint supplied is on the same subnet as this host
|
||||
@@ -276,10 +320,20 @@ namespace Lidgren.Network
|
||||
[CLSCompliant(false)]
|
||||
public static int BitsToHoldUInt(uint value)
|
||||
{
|
||||
int bits = 1;
|
||||
while ((value >>= 1) != 0)
|
||||
bits++;
|
||||
return bits;
|
||||
#if NETCOREAPP3_1
|
||||
return 32 - System.Numerics.BitOperations.LeadingZeroCount(value);
|
||||
#else
|
||||
value |= value >> 1;
|
||||
value |= value >> 2;
|
||||
value |= value >> 4;
|
||||
value |= value >> 8;
|
||||
value |= value >> 16;
|
||||
value -= ((value >> 1) & 0x55555555U);
|
||||
value = (value & 0x33333333U) + ((value >> 2) & 0x33333333U);
|
||||
value = (value + (value >> 4)) & 0x0F0F0F0FU;
|
||||
value = (value * 0x01010101U) >> 24;
|
||||
return (int)(value & 127);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -288,10 +342,22 @@ namespace Lidgren.Network
|
||||
[CLSCompliant(false)]
|
||||
public static int BitsToHoldUInt64(ulong value)
|
||||
{
|
||||
int bits = 1;
|
||||
while ((value >>= 1) != 0)
|
||||
bits++;
|
||||
return bits;
|
||||
#if NETCOREAPP3_1
|
||||
return 64 - System.Numerics.BitOperations.LeadingZeroCount(value);
|
||||
#else
|
||||
value |= value >> 1;
|
||||
value |= value >> 2;
|
||||
value |= value >> 4;
|
||||
value |= value >> 8;
|
||||
value |= value >> 16;
|
||||
value |= value >> 32;
|
||||
value -= ((value >> 1) & 0x5555555555555555U);
|
||||
value = (value & 0x3333333333333333U)
|
||||
+ ((value >> 2) & 0x3333333333333333U);
|
||||
value = (value + (value >> 4)) & 0x0F0F0F0F0F0F0F0FU;
|
||||
value = (value * 0x0101010101010101U) >> 56;
|
||||
return (int)(value & 127);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -302,28 +368,6 @@ namespace Lidgren.Network
|
||||
return (numBits + 7) / 8;
|
||||
}
|
||||
|
||||
internal static UInt32 SwapByteOrder(UInt32 value)
|
||||
{
|
||||
return
|
||||
((value & 0xff000000) >> 24) |
|
||||
((value & 0x00ff0000) >> 8) |
|
||||
((value & 0x0000ff00) << 8) |
|
||||
((value & 0x000000ff) << 24);
|
||||
}
|
||||
|
||||
internal static UInt64 SwapByteOrder(UInt64 value)
|
||||
{
|
||||
return
|
||||
((value & 0xff00000000000000L) >> 56) |
|
||||
((value & 0x00ff000000000000L) >> 40) |
|
||||
((value & 0x0000ff0000000000L) >> 24) |
|
||||
((value & 0x000000ff00000000L) >> 8) |
|
||||
((value & 0x00000000ff000000L) << 8) |
|
||||
((value & 0x0000000000ff0000L) << 24) |
|
||||
((value & 0x000000000000ff00L) << 40) |
|
||||
((value & 0x00000000000000ffL) << 56);
|
||||
}
|
||||
|
||||
internal static bool CompareElements(byte[] one, byte[] two)
|
||||
{
|
||||
if (one.Length != two.Length)
|
||||
@@ -337,12 +381,25 @@ namespace Lidgren.Network
|
||||
/// <summary>
|
||||
/// Convert a hexadecimal string to a byte array
|
||||
/// </summary>
|
||||
public static byte[] ToByteArray(String hexString)
|
||||
public static Span<byte> HexToBytes(String hexString, Span<byte> buffer)
|
||||
{
|
||||
byte[] retval = new byte[hexString.Length / 2];
|
||||
for (int i = 0; i < hexString.Length; i += 2)
|
||||
retval[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
|
||||
return retval;
|
||||
if (buffer.Length < hexString.Length/2)
|
||||
throw new ArgumentOutOfRangeException(nameof(buffer), buffer.Length,"Buffer too small");
|
||||
|
||||
var hexStrEnum = hexString.GetEnumerator();
|
||||
for (var i = 0; i+1 < hexString.Length; i += 2)
|
||||
{
|
||||
hexStrEnum.MoveNext();
|
||||
var chHi = hexStrEnum.Current;
|
||||
hexStrEnum.MoveNext();
|
||||
var chLo = hexStrEnum.Current;
|
||||
buffer[i / 2] = (byte)(
|
||||
(((chHi & 0xF) << 4) + ((chHi & 0x40)>>2) * 9)
|
||||
|((chLo & 0xF) + ((chLo & 0x40)>>6) * 9)
|
||||
);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -350,11 +407,10 @@ namespace Lidgren.Network
|
||||
/// </summary>
|
||||
public static string ToHumanReadable(long bytes)
|
||||
{
|
||||
if (bytes < 4000) // 1-4 kb is printed in bytes
|
||||
return bytes + " bytes";
|
||||
if (bytes < 1000 * 1000) // 4-999 kb is printed in kb
|
||||
return Math.Round(((double)bytes / 1000.0), 2) + " kilobytes";
|
||||
return Math.Round(((double)bytes / (1000.0 * 1000.0)), 2) + " megabytes"; // else megabytes
|
||||
var index = (long)Math.Round(Math.Max(0,Math.Log(bytes, 1024) - 2/3d), MidpointRounding.AwayFromZero);
|
||||
var denominator = Math.Pow(1024, index);
|
||||
|
||||
return $"{bytes / denominator:0.##} {ByteStringSuffixes[index]}";
|
||||
}
|
||||
|
||||
internal static int RelativeSequenceNumber(int nr, int expected)
|
||||
@@ -460,13 +516,7 @@ namespace Lidgren.Network
|
||||
return bdr.ToString();
|
||||
}
|
||||
|
||||
public static byte[] ComputeSHAHash(byte[] bytes)
|
||||
{
|
||||
// this is defined in the platform specific files
|
||||
return ComputeSHAHash(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Copies from <paramref name="src"/> to <paramref name="dst"/>. Maps to an IPv6 address
|
||||
/// </summary>
|
||||
/// <param name="src">Source.</param>
|
||||
|
||||
52
Lidgren.Network/Platform/NativeSocket.Structs.cs
Normal file
52
Lidgren.Network/Platform/NativeSocket.Structs.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#pragma warning disable 649
|
||||
namespace Lidgren.Network {
|
||||
|
||||
public static partial class NativeSockets {
|
||||
|
||||
[SuppressMessage("ReSharper", "FieldCanBeMadeReadOnly.Local")]
|
||||
[StructLayout(LayoutKind.Sequential, Size = SockAddrStorageSize)]
|
||||
private struct SockAddr {
|
||||
|
||||
public ushort SocketAddressFamily;
|
||||
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "NotAccessedField.Local")]
|
||||
private struct SockAddrIn {
|
||||
|
||||
public ushort SocketAddressFamily;
|
||||
|
||||
public ushort Port;
|
||||
|
||||
public uint InAddr;
|
||||
|
||||
public ulong Zero;
|
||||
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 16)]
|
||||
private struct InAddr6 {
|
||||
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "NotAccessedField.Local")]
|
||||
private struct SockAddrIn6 {
|
||||
|
||||
public ushort SocketAddressFamily;
|
||||
|
||||
public ushort Port;
|
||||
|
||||
public uint FlowInfo;
|
||||
|
||||
public InAddr6 InAddr;
|
||||
|
||||
public uint InScopeId;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
195
Lidgren.Network/Platform/NativeSockets.cs
Normal file
195
Lidgren.Network/Platform/NativeSockets.cs
Normal file
@@ -0,0 +1,195 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Lidgren.Network
|
||||
{
|
||||
|
||||
public static partial class NativeSockets
|
||||
{
|
||||
|
||||
private const int SockAddrStorageSize = 128; // sockaddr_storage
|
||||
|
||||
private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
|
||||
internal static unsafe int _SendTo(int socket, byte* buf, int len, int flags, void* to, int toLen)
|
||||
=> IsWindows
|
||||
? WindowsSockets.SendTo(socket, buf, len, flags, to, toLen)
|
||||
: PosixSockets.SendTo(socket, buf, len, flags, to, toLen);
|
||||
|
||||
internal static unsafe int _RecvFrom(int socket, byte* buf, int len, int flags, void* from, int* fromLen)
|
||||
=> IsWindows
|
||||
? WindowsSockets.RecvFrom(socket, buf, len, flags, from, fromLen)
|
||||
: PosixSockets.RecvFrom(socket, buf, len, flags, from, fromLen);
|
||||
|
||||
public static int GetError(Socket socket)
|
||||
=> (int) socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Error);
|
||||
|
||||
public static unsafe int SendTo(this Socket socket, ReadOnlySpan<byte> buffer, int flags, IPEndPoint to)
|
||||
{
|
||||
switch (to.AddressFamily)
|
||||
{
|
||||
default:
|
||||
throw new NotImplementedException(to.AddressFamily.ToString());
|
||||
|
||||
case AddressFamily.InterNetwork:
|
||||
{
|
||||
var error = 0;
|
||||
var addrIn = new SockAddrIn();
|
||||
var port = (ushort) to.Port;
|
||||
addrIn.SocketAddressFamily = (ushort) to.AddressFamily;
|
||||
addrIn.Port = BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(port) : port;
|
||||
if (!to.Address.TryWriteBytes(MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref addrIn.InAddr, 1)), out _))
|
||||
throw new NotImplementedException("Can't write address.");
|
||||
|
||||
int result;
|
||||
fixed (byte* pBuf = buffer)
|
||||
{
|
||||
result = _SendTo(socket.Handle.ToInt32(), pBuf, buffer.Length, flags, &addrIn, sizeof(SockAddrIn));
|
||||
}
|
||||
|
||||
if (result == -1)
|
||||
{
|
||||
error = GetError(socket);
|
||||
if (error == 0)
|
||||
error = Marshal.GetLastWin32Error();
|
||||
}
|
||||
|
||||
if (result == -1)
|
||||
throw new SocketException(error);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
case AddressFamily.InterNetworkV6:
|
||||
{
|
||||
var error = 0;
|
||||
var addrIn6 = new SockAddrIn6();
|
||||
var port = (ushort) to.Port;
|
||||
addrIn6.SocketAddressFamily = (ushort) to.AddressFamily;
|
||||
addrIn6.Port = BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(port) : port;
|
||||
if (!to.Address.TryWriteBytes(MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref addrIn6.InAddr, 1)), out _))
|
||||
throw new NotImplementedException("Can't write address.");
|
||||
|
||||
addrIn6.InScopeId = checked((uint) to.Address.ScopeId);
|
||||
int result;
|
||||
fixed (byte* pBuf = buffer)
|
||||
{
|
||||
result = _SendTo(socket.Handle.ToInt32(), pBuf, buffer.Length, flags, &addrIn6, sizeof(SockAddrIn6));
|
||||
}
|
||||
|
||||
if (result == -1)
|
||||
{
|
||||
error = GetError(socket);
|
||||
if (error == 0)
|
||||
error = Marshal.GetLastWin32Error();
|
||||
}
|
||||
|
||||
if (result == -1)
|
||||
throw new SocketException(error);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe int ReceiveFrom(this Socket socket, Span<byte> buffer, int flags, out IPEndPoint? from)
|
||||
{
|
||||
var error = 0;
|
||||
int result;
|
||||
var fromSockAddrSize = SockAddrStorageSize;
|
||||
var pFrom = stackalloc byte[SockAddrStorageSize];
|
||||
|
||||
fixed (byte* pBuf = buffer)
|
||||
{
|
||||
result = _RecvFrom(socket.Handle.ToInt32(), pBuf, buffer.Length, flags, pFrom, &fromSockAddrSize);
|
||||
}
|
||||
|
||||
if (result == -1)
|
||||
{
|
||||
error = GetError(socket);
|
||||
if (error == 0)
|
||||
{
|
||||
error = Marshal.GetLastWin32Error();
|
||||
}
|
||||
}
|
||||
|
||||
ReadIp(out from, (SockAddr*) pFrom);
|
||||
|
||||
if (result == -1)
|
||||
{
|
||||
throw new SocketException(error);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static unsafe void ReadIp(out IPEndPoint? from, SockAddr* pFrom)
|
||||
{
|
||||
switch (pFrom->SocketAddressFamily)
|
||||
{
|
||||
default:
|
||||
throw new NotSupportedException(((AddressFamily) pFrom->SocketAddressFamily).ToString());
|
||||
case (ushort) AddressFamily.Unspecified:
|
||||
from = null;
|
||||
break;
|
||||
case (ushort) AddressFamily.InterNetwork:
|
||||
ReadIPv4(out from, (SockAddrIn*) pFrom);
|
||||
break;
|
||||
case (ushort) AddressFamily.InterNetworkV6:
|
||||
ReadIPv6(out from, (SockAddrIn6*) pFrom);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe void ReadIPv4(out IPEndPoint from, SockAddrIn* addr)
|
||||
{
|
||||
var port = BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(addr->Port) : addr->Port;
|
||||
var ip = BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(addr->InAddr) : addr->InAddr;
|
||||
|
||||
from = new IPEndPoint(
|
||||
ip,
|
||||
port
|
||||
);
|
||||
}
|
||||
|
||||
private static unsafe void ReadIPv6(out IPEndPoint from, SockAddrIn6* addr)
|
||||
{
|
||||
var port = BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(addr->Port) : addr->Port;
|
||||
|
||||
var ip = new IPAddress(MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref addr->InAddr, 1)), addr->InScopeId);
|
||||
|
||||
from = new IPEndPoint(ip, port);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal static class PosixSockets
|
||||
{
|
||||
|
||||
[DllImport("libc", EntryPoint = "sendto")]
|
||||
internal static extern unsafe int SendTo(int socket, byte* buf, int len, int flags, void* to, int toLen);
|
||||
|
||||
[DllImport("libc", EntryPoint = "recvfrom")]
|
||||
internal static extern unsafe int RecvFrom(int socket, byte* buf, int len, int flags, void* from, int* fromLen);
|
||||
|
||||
}
|
||||
|
||||
internal static class WindowsSockets
|
||||
{
|
||||
|
||||
[DllImport("ws2_32", EntryPoint = "sendto")]
|
||||
internal static extern unsafe int SendTo(int socket, byte* buf, int len, int flags, void* to, int toLen);
|
||||
|
||||
[DllImport("ws2_32", EntryPoint = "recvfrom")]
|
||||
internal static extern unsafe int RecvFrom(int socket, byte* buf, int len, int flags, void* from, int* fromLen);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -69,10 +69,11 @@ namespace Lidgren.Network
|
||||
return new IPAddress(bytes);
|
||||
}
|
||||
|
||||
private static readonly SHA1 s_sha = SHA1.Create();
|
||||
public static byte[] ComputeSHAHash(byte[] bytes, int offset, int count)
|
||||
private static readonly SHA256 s_sha = SHA256.Create();
|
||||
|
||||
public static bool ComputeSHAHash(ReadOnlySpan<byte> src, Span<byte> dest)
|
||||
{
|
||||
return s_sha.ComputeHash(bytes, offset, count);
|
||||
return s_sha.TryComputeHash(src, dest, out _);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
@@ -130,15 +131,21 @@ namespace Lidgren.Network
|
||||
System.Threading.Thread.Sleep(milliseconds);
|
||||
}
|
||||
|
||||
public static IPAddress CreateAddressFromBytes(byte[] bytes)
|
||||
public static IPAddress CreateAddressFromBytes(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
return new IPAddress(bytes);
|
||||
}
|
||||
|
||||
private static readonly SHA256 s_sha = SHA256.Create();
|
||||
public static byte[] ComputeSHAHash(byte[] bytes, int offset, int count)
|
||||
|
||||
public static readonly int SHAHashSize = 256;
|
||||
|
||||
public static Span<byte> ComputeSHAHash(ReadOnlySpan<byte> src, Span<byte> dest)
|
||||
{
|
||||
return s_sha.ComputeHash(bytes, offset, count);
|
||||
if (!s_sha.TryComputeHash(src, dest, out _))
|
||||
throw new InvalidOperationException("Can't compute hash");
|
||||
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Lidgren.Network")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
||||
[assembly: AssemblyCopyright("Copyright © Lidgren 2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
@@ -32,6 +32,6 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("2012.1.7.0")]
|
||||
[assembly: AssemblyFileVersion("2012.1.7.0")]
|
||||
[assembly: System.CLSCompliant(true)]
|
||||
[assembly: AssemblyVersion("2020.7.0.0")]
|
||||
[assembly: AssemblyFileVersion("2020.7.0.0")]
|
||||
[assembly: System.CLSCompliant(false)]
|
||||
@@ -0,0 +1,216 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Lidgren.Network
|
||||
{
|
||||
|
||||
public partial class NetBuffer
|
||||
{
|
||||
|
||||
public class AppenderStream : Stream
|
||||
{
|
||||
|
||||
internal AppenderStream(NetBuffer netBuffer)
|
||||
{
|
||||
Buffer = netBuffer;
|
||||
}
|
||||
|
||||
protected NetBuffer Buffer;
|
||||
|
||||
protected override void Dispose(bool _)
|
||||
=> Buffer = null;
|
||||
|
||||
protected void DisposedCheck()
|
||||
{
|
||||
if (Buffer == null) throw new ObjectDisposedException("Stream");
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override long Length => throw new NotSupportedException();
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => throw new NotSupportedException();
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Flush() => DisposedCheck();
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public override int Read(Span<byte> buffer)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public override void SetLength(long value)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
=> Write(new ReadOnlySpan<byte>(buffer, offset, count));
|
||||
|
||||
public override void Write(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(buffer));
|
||||
}
|
||||
|
||||
Buffer.Write(buffer);
|
||||
}
|
||||
|
||||
public override bool CanRead => false;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
}
|
||||
|
||||
public abstract class WrapperStream : Stream, IDisposable
|
||||
{
|
||||
|
||||
protected WrapperStream(NetBuffer netBuffer, in int start, int length, bool isReadMode)
|
||||
{
|
||||
NetException.Assert(netBuffer.m_bitLength - start >= length,
|
||||
isReadMode ? c_readOverflowError : c_writeOverflowError);
|
||||
|
||||
Buffer = netBuffer;
|
||||
BitOffsetStart = start;
|
||||
BitOffset = start;
|
||||
BitOffsetEnd = start + length;
|
||||
}
|
||||
|
||||
protected NetBuffer Buffer;
|
||||
|
||||
protected int BitOffsetStart;
|
||||
|
||||
protected int BitOffsetEnd;
|
||||
|
||||
protected int BitOffset;
|
||||
|
||||
protected override void Dispose(bool _)
|
||||
=> Buffer = null;
|
||||
|
||||
protected void DisposedCheck()
|
||||
{
|
||||
if (Buffer == null) throw new ObjectDisposedException("Stream");
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
DisposedCheck();
|
||||
switch (origin)
|
||||
{
|
||||
case SeekOrigin.Begin: break;
|
||||
case SeekOrigin.Current:
|
||||
offset += Position;
|
||||
break;
|
||||
case SeekOrigin.End:
|
||||
offset = Position - offset;
|
||||
break;
|
||||
default: throw new ArgumentOutOfRangeException(nameof(origin), origin, "SeekOrigin invalid.");
|
||||
}
|
||||
|
||||
return Position = offset;
|
||||
}
|
||||
|
||||
public override long Length => (BitOffsetStart - BitOffsetEnd) >> 3;
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => (BitOffset - BitOffsetStart) >> 3;
|
||||
set => BitOffset = BitOffsetStart + (checked((int)value) << 3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class ReadOnlyWrapperStream : WrapperStream
|
||||
{
|
||||
|
||||
internal ReadOnlyWrapperStream(NetBuffer netBuffer, int start, int length)
|
||||
: base(netBuffer, start, length, true)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Flush() => DisposedCheck();
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
=> Read(new Span<byte>(buffer, offset, count));
|
||||
|
||||
public override int Read(Span<byte> buffer)
|
||||
{
|
||||
DisposedCheck();
|
||||
var numberOfBytes = buffer.Length;
|
||||
var numberOfBits = numberOfBytes * 8;
|
||||
NetException.Assert(BitOffsetEnd - BitOffset >= numberOfBits, c_readOverflowError);
|
||||
NetBitWriter.ReadBytes(Buffer.m_data, numberOfBytes, BitOffset, buffer, 0);
|
||||
BitOffset += numberOfBits;
|
||||
return buffer.Length;
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public override bool CanRead => BitOffset < BitOffsetEnd;
|
||||
|
||||
public override bool CanSeek => true;
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class WriteOnlyWrapperStream : WrapperStream
|
||||
{
|
||||
|
||||
internal WriteOnlyWrapperStream(NetBuffer netBuffer, int start, int length)
|
||||
: base(netBuffer, start, length, false)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Flush() => DisposedCheck();
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public override int Read(Span<byte> buffer)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public override void SetLength(long value)
|
||||
=> throw new NotSupportedException();
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
=> Write(new ReadOnlySpan<byte>(buffer, offset, count));
|
||||
|
||||
public override void Write(ReadOnlySpan<byte> buffer)
|
||||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(buffer));
|
||||
}
|
||||
|
||||
var numberOfBytes = buffer.Length;
|
||||
var numberOfBits = numberOfBytes * 8;
|
||||
NetException.Assert(BitOffsetEnd - BitOffset >= numberOfBits, c_writeOverflowError);
|
||||
NetBitWriter.WriteBytes(buffer, 0, numberOfBytes, Buffer.m_data, BitOffset);
|
||||
BitOffset += numberOfBits;
|
||||
}
|
||||
|
||||
public override bool CanRead => false;
|
||||
|
||||
public override bool CanSeek => true;
|
||||
|
||||
public override bool CanWrite => BitOffset < BitOffsetEnd;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -50,7 +50,7 @@ namespace Robust.Server.GameObjects
|
||||
return true;
|
||||
}
|
||||
|
||||
data = default;
|
||||
data = default!;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -272,7 +272,7 @@ namespace Robust.Server.GameObjects
|
||||
{
|
||||
foreach (var child in children)
|
||||
{
|
||||
var ent = child;
|
||||
var ent = child!;
|
||||
|
||||
do
|
||||
{
|
||||
@@ -280,7 +280,7 @@ namespace Robust.Server.GameObjects
|
||||
{
|
||||
AddContainedRecursive(ent, set);
|
||||
|
||||
ent = ent.Transform.Parent?.Owner;
|
||||
ent = ent.Transform.Parent?.Owner!;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -42,11 +42,9 @@ namespace Robust.Shared.Network.Messages
|
||||
case EntityMessageType.SystemMessage:
|
||||
{
|
||||
var serializer = IoCManager.Resolve<IRobustSerializer>();
|
||||
int messageLength = buffer.ReadInt32();
|
||||
using (var stream = new MemoryStream(buffer.ReadBytes(messageLength)))
|
||||
{
|
||||
SystemMessage = serializer.Deserialize<EntitySystemMessage>(stream);
|
||||
}
|
||||
int length = buffer.ReadInt32();
|
||||
using var stream = buffer.ReadAsStream(length);
|
||||
SystemMessage = serializer.Deserialize<EntitySystemMessage>(stream);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -56,11 +54,9 @@ namespace Robust.Shared.Network.Messages
|
||||
NetId = buffer.ReadUInt32();
|
||||
|
||||
var serializer = IoCManager.Resolve<IRobustSerializer>();
|
||||
int messageLength = buffer.ReadInt32();
|
||||
using (var stream = new MemoryStream(buffer.ReadBytes(messageLength)))
|
||||
{
|
||||
ComponentMessage = serializer.Deserialize<ComponentMessage>(stream);
|
||||
}
|
||||
int length = buffer.ReadInt32();
|
||||
using var stream = buffer.ReadAsStream(length);
|
||||
ComponentMessage = serializer.Deserialize<ComponentMessage>(stream);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -188,6 +184,7 @@ namespace Robust.Shared.Network.Messages
|
||||
}
|
||||
}
|
||||
|
||||
#if false
|
||||
private List<object> UnPackParams(NetIncomingMessage message)
|
||||
{
|
||||
var messageParams = new List<object>();
|
||||
@@ -236,12 +233,15 @@ namespace Robust.Shared.Network.Messages
|
||||
break;
|
||||
case NetworkDataType.d_byteArray:
|
||||
int length = message.ReadInt32();
|
||||
messageParams.Add(message.ReadBytes(length));
|
||||
var buf = new byte[length];
|
||||
message.ReadBytes(buf);
|
||||
messageParams.Add(buf)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return messageParams;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion Parameter Packing
|
||||
|
||||
|
||||
@@ -39,11 +39,9 @@ namespace Robust.Shared.Network.Messages
|
||||
var serializer = IoCManager.Resolve<IRobustSerializer>();
|
||||
|
||||
var length = buffer.ReadVariableInt32();
|
||||
var stateData = buffer.ReadBytes(length);
|
||||
|
||||
using var memoryStream = new MemoryStream(stateData);
|
||||
Echo = serializer.Deserialize<FormattedMessage>(memoryStream);
|
||||
Response = serializer.Deserialize<FormattedMessage>(memoryStream);
|
||||
using var stream = buffer.ReadAsStream(length);
|
||||
Echo = serializer.Deserialize<FormattedMessage>(stream);
|
||||
Response = serializer.Deserialize<FormattedMessage>(stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,12 +37,9 @@ namespace Robust.Shared.Network.Messages
|
||||
{
|
||||
MsgSize = buffer.LengthBytes;
|
||||
var length = buffer.ReadVariableInt32();
|
||||
var stateData = buffer.ReadBytes(length);
|
||||
using (var stateStream = new MemoryStream(stateData))
|
||||
{
|
||||
var serializer = IoCManager.Resolve<IRobustSerializer>();
|
||||
State = serializer.Deserialize<GameState>(stateStream);
|
||||
}
|
||||
using var stream = buffer.ReadAsStream(length);
|
||||
var serializer = IoCManager.Resolve<IRobustSerializer>();
|
||||
State = serializer.Deserialize<GameState>(stream);
|
||||
|
||||
State.PayloadSize = length;
|
||||
}
|
||||
|
||||
@@ -42,19 +42,13 @@ namespace Robust.Shared.Network.Messages
|
||||
SessionId = buffer.ReadUInt32();
|
||||
{
|
||||
var length = buffer.ReadInt32();
|
||||
var bytes = buffer.ReadBytes(length);
|
||||
using (var stream = new MemoryStream(bytes))
|
||||
{
|
||||
PropertyIndex = serializer.Deserialize<object[]>(stream);
|
||||
}
|
||||
using var stream = buffer.ReadAsStream(length);
|
||||
PropertyIndex = serializer.Deserialize<object[]>(stream);
|
||||
}
|
||||
{
|
||||
var length = buffer.ReadInt32();
|
||||
var bytes = buffer.ReadBytes(length);
|
||||
using (var stream = new MemoryStream(bytes))
|
||||
{
|
||||
Value = serializer.Deserialize(stream);
|
||||
}
|
||||
using var stream = buffer.ReadAsStream(length);
|
||||
Value = serializer.Deserialize(stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,11 +41,8 @@ namespace Robust.Shared.Network.Messages
|
||||
RequestId = buffer.ReadUInt32();
|
||||
var serializer = IoCManager.Resolve<IRobustSerializer>();
|
||||
var length = buffer.ReadInt32();
|
||||
var bytes = buffer.ReadBytes(length);
|
||||
using (var stream = new MemoryStream(bytes))
|
||||
{
|
||||
Blob = serializer.Deserialize<ViewVariablesBlob>(stream);
|
||||
}
|
||||
using var stream = buffer.ReadAsStream(length);
|
||||
Blob = serializer.Deserialize<ViewVariablesBlob>(stream);
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
||||
|
||||
@@ -47,11 +47,8 @@ namespace Robust.Shared.Network.Messages
|
||||
SessionId = buffer.ReadUInt32();
|
||||
var serializer = IoCManager.Resolve<IRobustSerializer>();
|
||||
var length = buffer.ReadInt32();
|
||||
var bytes = buffer.ReadBytes(length);
|
||||
using (var stream = new MemoryStream(bytes))
|
||||
{
|
||||
RequestMeta = serializer.Deserialize<ViewVariablesRequest>(stream);
|
||||
}
|
||||
using var stream = buffer.ReadAsStream(length);
|
||||
RequestMeta = serializer.Deserialize<ViewVariablesRequest>(stream);
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
||||
@@ -68,4 +65,3 @@ namespace Robust.Shared.Network.Messages
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,11 +43,8 @@ namespace Robust.Shared.Network.Messages
|
||||
RequestId = buffer.ReadUInt32();
|
||||
var serializer = IoCManager.Resolve<IRobustSerializer>();
|
||||
var length = buffer.ReadInt32();
|
||||
var bytes = buffer.ReadBytes(length);
|
||||
using (var stream = new MemoryStream(bytes))
|
||||
{
|
||||
Selector = serializer.Deserialize<ViewVariablesObjectSelector>(stream);
|
||||
}
|
||||
using var stream = buffer.ReadAsStream(length);
|
||||
Selector = serializer.Deserialize<ViewVariablesObjectSelector>(stream);
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
||||
|
||||
@@ -6,6 +6,7 @@ using Robust.Shared.Network;
|
||||
|
||||
namespace Robust.Shared.Serialization
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The server part of the string-exchange handshake. Sent as the
|
||||
/// first message in the handshake. Tells the client the hash of
|
||||
@@ -35,7 +36,7 @@ namespace Robust.Shared.Serialization
|
||||
throw new InvalidOperationException("Hash too long.");
|
||||
}
|
||||
|
||||
Hash = buffer.ReadBytes(len);
|
||||
buffer.ReadBytes(Hash = new byte[len]);
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using JetBrains.Annotations;
|
||||
using Lidgren.Network;
|
||||
@@ -7,6 +8,7 @@ using Robust.Shared.Network;
|
||||
|
||||
namespace Robust.Shared.Serialization
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// The meat of the string-exchange handshake sandwich. Sent by the
|
||||
/// server after the client requests an updated copy of the mapping.
|
||||
@@ -22,6 +24,8 @@ namespace Robust.Shared.Serialization
|
||||
{
|
||||
}
|
||||
|
||||
public int PackageSize { get; set; }
|
||||
|
||||
/// <value>
|
||||
/// The raw bytes of the string mapping held by the server.
|
||||
/// </value>
|
||||
@@ -29,14 +33,8 @@ namespace Robust.Shared.Serialization
|
||||
|
||||
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
||||
{
|
||||
var l = buffer.ReadVariableInt32();
|
||||
var success = buffer.ReadBytes(l, out var buf);
|
||||
if (!success)
|
||||
{
|
||||
throw new InvalidDataException("Not all of the bytes were available in the message.");
|
||||
}
|
||||
|
||||
Package = buf;
|
||||
PackageSize = buffer.ReadVariableInt32();
|
||||
buffer.ReadBytes(Package = new byte[PackageSize]);
|
||||
}
|
||||
|
||||
public override void WriteToBuffer(NetOutgoingMessage buffer)
|
||||
|
||||
Reference in New Issue
Block a user