quantum-space-buddies/QuantumUNET/QSBChannelBuffer.cs

398 lines
9.5 KiB
C#
Raw Normal View History

2020-12-02 18:40:38 +00:00
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
2020-12-04 22:14:53 +00:00
namespace QuantumUNET
2020-12-02 18:40:38 +00:00
{
2020-12-03 08:28:05 +00:00
internal class QSBChannelBuffer : IDisposable
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
public int NumMsgsOut { get; private set; }
public int NumBufferedMsgsOut { get; private set; }
public int NumBytesOut { get; private set; }
public int NumMsgsIn { get; private set; }
public int NumBytesIn { get; private set; }
public int NumBufferedPerSecond { get; private set; }
public int LastBufferedPerSecond { get; private set; }
public const int MaxPendingPacketCount = 16;
public const int MaxBufferedPackets = 512;
public float MaxDelay = 0.01f;
private QSBNetworkConnection _connection;
private QSBChannelPacket _currentPacket;
private float _lastFlushTime;
private byte _channelId;
private int _maxPacketSize;
private bool _isReliable;
private bool _allowFragmentation;
private bool _isBroken;
private int _maxPendingPacketCount;
private const int _maxFreePacketCount = 512;
private Queue<QSBChannelPacket> _pendingPackets;
private static List<QSBChannelPacket> _freePackets;
internal static int _pendingPacketCount;
private float _lastBufferedMessageCountTimer = Time.realtimeSinceStartup;
2020-12-04 09:23:27 +00:00
private static QSBNetworkWriter _sendWriter = new QSBNetworkWriter();
private static QSBNetworkWriter _fragmentWriter = new QSBNetworkWriter();
2020-12-03 11:56:32 +00:00
private const int _packetHeaderReserveSize = 100;
private bool _disposed;
internal QSBNetBuffer _fragmentBuffer = new QSBNetBuffer();
private bool _readingFragment = false;
2020-12-02 18:40:38 +00:00
public QSBChannelBuffer(QSBNetworkConnection conn, int bufferSize, byte cid, bool isReliable, bool isSequenced)
{
2020-12-03 11:56:32 +00:00
_connection = conn;
_maxPacketSize = bufferSize - 100;
_currentPacket = new QSBChannelPacket(_maxPacketSize, isReliable);
_channelId = cid;
_maxPendingPacketCount = 16;
_isReliable = isReliable;
_allowFragmentation = isReliable && isSequenced;
2020-12-02 18:40:38 +00:00
if (isReliable)
{
2020-12-03 11:56:32 +00:00
_pendingPackets = new Queue<QSBChannelPacket>();
if (_freePackets == null)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
_freePackets = new List<QSBChannelPacket>();
2020-12-02 18:40:38 +00:00
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
2020-12-03 11:56:32 +00:00
if (!_disposed && disposing)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
if (_pendingPackets != null)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
while (_pendingPackets.Count > 0)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
_pendingPacketCount--;
var item = _pendingPackets.Dequeue();
if (_freePackets.Count < 512)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
_freePackets.Add(item);
2020-12-02 18:40:38 +00:00
}
}
2020-12-03 11:56:32 +00:00
_pendingPackets.Clear();
2020-12-02 18:40:38 +00:00
}
}
2020-12-03 11:56:32 +00:00
_disposed = true;
2020-12-02 18:40:38 +00:00
}
public bool SetOption(ChannelOption option, int value)
{
bool result;
if (option != ChannelOption.MaxPendingBuffers)
{
if (option != ChannelOption.AllowFragmentation)
{
if (option != ChannelOption.MaxPacketSize)
{
result = false;
}
2020-12-03 11:56:32 +00:00
else if (!_currentPacket.IsEmpty() || _pendingPackets.Count > 0)
2020-12-02 18:40:38 +00:00
{
if (LogFilter.logError)
{
Debug.LogError("Cannot set MaxPacketSize after sending data.");
}
result = false;
}
else if (value <= 0)
{
if (LogFilter.logError)
{
Debug.LogError("Cannot set MaxPacketSize less than one.");
}
result = false;
}
2020-12-03 11:56:32 +00:00
else if (value > _maxPacketSize)
2020-12-02 18:40:38 +00:00
{
if (LogFilter.logError)
{
2020-12-03 11:56:32 +00:00
Debug.LogError("Cannot set MaxPacketSize to greater than the existing maximum (" + _maxPacketSize + ").");
2020-12-02 18:40:38 +00:00
}
result = false;
}
else
{
2020-12-03 11:56:32 +00:00
_currentPacket = new QSBChannelPacket(value, _isReliable);
_maxPacketSize = value;
2020-12-02 18:40:38 +00:00
result = true;
}
}
else
{
2020-12-03 11:56:32 +00:00
_allowFragmentation = value != 0;
2020-12-02 18:40:38 +00:00
result = true;
}
}
2020-12-03 11:56:32 +00:00
else if (!_isReliable)
2020-12-02 18:40:38 +00:00
{
result = false;
}
else if (value < 0 || value >= 512)
{
if (LogFilter.logError)
{
Debug.LogError(string.Concat(new object[]
{
"Invalid MaxPendingBuffers for channel ",
2020-12-03 11:56:32 +00:00
_channelId,
2020-12-02 18:40:38 +00:00
". Must be greater than zero and less than ",
512
}));
}
result = false;
}
else
{
2020-12-03 11:56:32 +00:00
_maxPendingPacketCount = value;
2020-12-02 18:40:38 +00:00
result = true;
}
return result;
}
public void CheckInternalBuffer()
{
2020-12-03 11:56:32 +00:00
if (Time.realtimeSinceStartup - _lastFlushTime > MaxDelay && !_currentPacket.IsEmpty())
2020-12-02 18:40:38 +00:00
{
SendInternalBuffer();
2020-12-03 11:56:32 +00:00
_lastFlushTime = Time.realtimeSinceStartup;
2020-12-02 18:40:38 +00:00
}
2020-12-03 11:56:32 +00:00
if (Time.realtimeSinceStartup - _lastBufferedMessageCountTimer > 1f)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
LastBufferedPerSecond = NumBufferedPerSecond;
NumBufferedPerSecond = 0;
_lastBufferedMessageCountTimer = Time.realtimeSinceStartup;
2020-12-02 18:40:38 +00:00
}
}
2020-12-04 09:23:27 +00:00
public bool SendWriter(QSBNetworkWriter writer)
2020-12-02 18:40:38 +00:00
{
2020-12-04 21:04:18 +00:00
var arraySegment = writer.AsArraySegment();
2020-12-02 21:19:10 +00:00
return SendBytes(arraySegment.Array, arraySegment.Count);
2020-12-02 18:40:38 +00:00
}
2020-12-04 09:23:27 +00:00
public bool Send(short msgType, QSBMessageBase msg)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
_sendWriter.StartMessage(msgType);
msg.Serialize(_sendWriter);
_sendWriter.FinishMessage();
NumMsgsOut++;
return SendWriter(_sendWriter);
2020-12-02 18:40:38 +00:00
}
2020-12-04 09:23:27 +00:00
internal bool HandleFragment(QSBNetworkReader reader)
2020-12-02 18:40:38 +00:00
{
bool result;
if (reader.ReadByte() == 0)
{
2020-12-03 11:56:32 +00:00
if (!_readingFragment)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
_fragmentBuffer.SeekZero();
_readingFragment = true;
2020-12-02 18:40:38 +00:00
}
2020-12-02 21:19:10 +00:00
var array = reader.ReadBytesAndSize();
2020-12-03 11:56:32 +00:00
_fragmentBuffer.WriteBytes(array, (ushort)array.Length);
2020-12-02 18:40:38 +00:00
result = false;
}
else
{
2020-12-03 11:56:32 +00:00
_readingFragment = false;
2020-12-02 18:40:38 +00:00
result = true;
}
return result;
}
internal bool SendFragmentBytes(byte[] bytes, int bytesToSend)
{
2020-12-02 21:19:10 +00:00
var num = 0;
2020-12-02 18:40:38 +00:00
while (bytesToSend > 0)
{
2020-12-03 11:56:32 +00:00
var num2 = Math.Min(bytesToSend, _maxPacketSize - 32);
2020-12-02 21:19:10 +00:00
var array = new byte[num2];
2020-12-02 18:40:38 +00:00
Array.Copy(bytes, num, array, 0, num2);
2020-12-03 11:56:32 +00:00
_fragmentWriter.StartMessage(17);
_fragmentWriter.Write(0);
_fragmentWriter.WriteBytesFull(array);
_fragmentWriter.FinishMessage();
SendWriter(_fragmentWriter);
2020-12-02 18:40:38 +00:00
num += num2;
bytesToSend -= num2;
}
2020-12-03 11:56:32 +00:00
_fragmentWriter.StartMessage(17);
_fragmentWriter.Write(1);
_fragmentWriter.FinishMessage();
SendWriter(_fragmentWriter);
2020-12-02 18:40:38 +00:00
return true;
}
internal bool SendBytes(byte[] bytes, int bytesToSend)
{
bool result;
if (bytesToSend >= 65535)
{
if (LogFilter.logError)
{
Debug.LogError("ChannelBuffer:SendBytes cannot send packet larger than " + ushort.MaxValue + " bytes");
}
result = false;
}
else if (bytesToSend <= 0)
{
if (LogFilter.logError)
{
Debug.LogError("ChannelBuffer:SendBytes cannot send zero bytes");
}
result = false;
}
2020-12-03 11:56:32 +00:00
else if (bytesToSend > _maxPacketSize)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
if (_allowFragmentation)
2020-12-02 18:40:38 +00:00
{
result = SendFragmentBytes(bytes, bytesToSend);
}
else
{
if (LogFilter.logError)
{
Debug.LogError(string.Concat(new object[]
{
"Failed to send big message of ",
bytesToSend,
" bytes. The maximum is ",
2020-12-03 11:56:32 +00:00
_maxPacketSize,
2020-12-02 18:40:38 +00:00
" bytes on channel:",
2020-12-03 11:56:32 +00:00
_channelId
2020-12-02 18:40:38 +00:00
}));
}
result = false;
}
}
2020-12-03 11:56:32 +00:00
else if (!_currentPacket.HasSpace(bytesToSend))
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
if (_isReliable)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
if (_pendingPackets.Count == 0)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
if (!_currentPacket.SendToTransport(_connection, _channelId))
2020-12-02 18:40:38 +00:00
{
QueuePacket();
}
2020-12-03 11:56:32 +00:00
_currentPacket.Write(bytes, bytesToSend);
2020-12-02 18:40:38 +00:00
result = true;
}
2020-12-03 11:56:32 +00:00
else if (_pendingPackets.Count >= _maxPendingPacketCount)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
if (!_isBroken)
2020-12-02 18:40:38 +00:00
{
if (LogFilter.logError)
{
2020-12-03 11:56:32 +00:00
Debug.LogError("ChannelBuffer buffer limit of " + _pendingPackets.Count + " packets reached.");
2020-12-02 18:40:38 +00:00
}
}
2020-12-03 11:56:32 +00:00
_isBroken = true;
2020-12-02 18:40:38 +00:00
result = false;
}
else
{
QueuePacket();
2020-12-03 11:56:32 +00:00
_currentPacket.Write(bytes, bytesToSend);
2020-12-02 18:40:38 +00:00
result = true;
}
}
2020-12-03 11:56:32 +00:00
else if (!_currentPacket.SendToTransport(_connection, _channelId))
2020-12-02 18:40:38 +00:00
{
if (LogFilter.logError)
{
2020-12-03 11:56:32 +00:00
Debug.Log("ChannelBuffer SendBytes no space on unreliable channel " + _channelId);
2020-12-02 18:40:38 +00:00
}
result = false;
}
else
{
2020-12-03 11:56:32 +00:00
_currentPacket.Write(bytes, bytesToSend);
2020-12-02 18:40:38 +00:00
result = true;
}
}
else
{
2020-12-03 11:56:32 +00:00
_currentPacket.Write(bytes, bytesToSend);
result = MaxDelay != 0f || SendInternalBuffer();
2020-12-02 18:40:38 +00:00
}
return result;
}
private void QueuePacket()
{
2020-12-03 11:56:32 +00:00
_pendingPacketCount++;
_pendingPackets.Enqueue(_currentPacket);
_currentPacket = AllocPacket();
2020-12-02 18:40:38 +00:00
}
private QSBChannelPacket AllocPacket()
{
QSBChannelPacket result;
2020-12-03 11:56:32 +00:00
if (_freePackets.Count == 0)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
result = new QSBChannelPacket(_maxPacketSize, _isReliable);
2020-12-02 18:40:38 +00:00
}
else
{
2020-12-03 11:56:32 +00:00
var channelPacket = _freePackets[_freePackets.Count - 1];
_freePackets.RemoveAt(_freePackets.Count - 1);
2020-12-02 18:40:38 +00:00
channelPacket.Reset();
result = channelPacket;
}
return result;
}
private static void FreePacket(QSBChannelPacket packet)
{
2020-12-03 11:56:32 +00:00
if (_freePackets.Count < 512)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
_freePackets.Add(packet);
2020-12-02 18:40:38 +00:00
}
}
public bool SendInternalBuffer()
{
bool result;
2020-12-03 11:56:32 +00:00
if (_isReliable && _pendingPackets.Count > 0)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
while (_pendingPackets.Count > 0)
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
var channelPacket = _pendingPackets.Dequeue();
if (!channelPacket.SendToTransport(_connection, _channelId))
2020-12-02 18:40:38 +00:00
{
2020-12-03 11:56:32 +00:00
_pendingPackets.Enqueue(channelPacket);
2020-12-02 18:40:38 +00:00
break;
}
2020-12-03 11:56:32 +00:00
_pendingPacketCount--;
2020-12-02 18:40:38 +00:00
FreePacket(channelPacket);
2020-12-03 11:56:32 +00:00
if (_isBroken && _pendingPackets.Count < _maxPendingPacketCount / 2)
2020-12-02 18:40:38 +00:00
{
if (LogFilter.logWarn)
{
Debug.LogWarning("ChannelBuffer recovered from overflow but data was lost.");
}
2020-12-03 11:56:32 +00:00
_isBroken = false;
2020-12-02 18:40:38 +00:00
}
}
result = true;
}
else
{
2020-12-03 11:56:32 +00:00
result = _currentPacket.SendToTransport(_connection, _channelId);
2020-12-02 18:40:38 +00:00
}
return result;
}
}
2020-12-03 08:28:05 +00:00
}