From 8a74186030cfa90ac93fc16df9f5aea20883cbfc Mon Sep 17 00:00:00 2001 From: Forest Date: Fri, 4 Jan 2019 16:57:43 -0800 Subject: [PATCH] Readd TCP capability, this helps deal with the lack of fragmented messaging in UDP. My usage is only server side when connections should be very reliable. I'll never use TCP in a game. --- Hazel/Connection.cs | 27 +-- Hazel/ConnectionListener.cs | 6 +- Hazel/DataReceivedEventArgs.cs | 46 +---- Hazel/Hazel.csproj | 3 + Hazel/MessageReader.cs | 10 + Hazel/MessageWriter.cs | 19 +- Hazel/NetworkConnection.cs | 33 +++ Hazel/NewConnectionEventArgs.cs | 54 +---- Hazel/SendOption.cs | 2 + Hazel/Tcp/StateObject.cs | 43 ++++ Hazel/Tcp/TcpConnection.cs | 310 ++++++++++++++++++++++++++++ Hazel/Tcp/TcpConnectionListener.cs | 92 +++++++++ Hazel/Udp/UdpClientConnection.cs | 2 +- Hazel/Udp/UdpConnection.Reliable.cs | 2 +- Hazel/Udp/UdpConnection.cs | 74 +------ Hazel/Udp/UdpServerConnection.cs | 4 +- 16 files changed, 539 insertions(+), 188 deletions(-) create mode 100644 Hazel/Tcp/StateObject.cs create mode 100644 Hazel/Tcp/TcpConnection.cs create mode 100644 Hazel/Tcp/TcpConnectionListener.cs diff --git a/Hazel/Connection.cs b/Hazel/Connection.cs index 5e14cc6..998fe6a 100644 --- a/Hazel/Connection.cs +++ b/Hazel/Connection.cs @@ -48,7 +48,7 @@ namespace Hazel /// /// /// - public Action DataReceived; + public event Action DataReceived; public int TestLagMs = -1; @@ -174,24 +174,7 @@ namespace Hazel /// /// public abstract void SendBytes(byte[] bytes, SendOption sendOption = SendOption.None); - - /// - /// Sends a number of bytes to the end point of the connection using the specified . - /// - /// The bytes of the message to send. - /// - /// - /// The option specifying how the message should be sent. - /// - /// - /// - /// The sendOptions parameter is only a request to use those options and the actual method used to send the - /// data is up to the implementation. There are circumstances where this parameter may be ignored but in - /// general any implementer should aim to always follow the user's request. - /// - /// - public abstract void SendBytes(byte[] bytes, int offset, int length, SendOption sendOption = SendOption.None); - + /// /// Connects the connection to a server and begins listening. /// @@ -232,15 +215,13 @@ namespace Hazel /// received. The bytes and the send option that the message was sent with should be passed in to give to the /// subscribers. /// - protected void InvokeDataReceived(MessageReader msg, SendOption sendOption, ushort reliableId) + protected void InvokeDataReceived(MessageReader msg, SendOption sendOption) { //Make a copy to avoid race condition between null check and invocation Action handler = DataReceived; if (handler != null) { - DataReceivedEventArgs args = DataReceivedEventArgs.GetObject(); - args.Set(msg, sendOption, reliableId); - handler.Invoke(args); + handler(new DataReceivedEventArgs(msg, sendOption)); } else { diff --git a/Hazel/ConnectionListener.cs b/Hazel/ConnectionListener.cs index fde09c6..20064e3 100644 --- a/Hazel/ConnectionListener.cs +++ b/Hazel/ConnectionListener.cs @@ -46,7 +46,7 @@ namespace Hazel /// /// /// - public Action NewConnection; + public event Action NewConnection; /// /// Makes this connection listener begin listening for connections. @@ -80,9 +80,7 @@ namespace Hazel Action handler = NewConnection; if (handler != null) { - NewConnectionEventArgs args = NewConnectionEventArgs.GetObject(); - args.Set(msg, connection); - handler(args); + handler(new NewConnectionEventArgs(msg, connection)); } else { diff --git a/Hazel/DataReceivedEventArgs.cs b/Hazel/DataReceivedEventArgs.cs index 1d6ea51..a063852 100644 --- a/Hazel/DataReceivedEventArgs.cs +++ b/Hazel/DataReceivedEventArgs.cs @@ -5,58 +5,22 @@ using System.Text; namespace Hazel { - /// - /// Event arguments for the event. - /// - /// - /// - /// This contains information about messages received by a connection and is passed to subscribers of the - /// DataEvent. - /// - /// - /// - /// - public class DataReceivedEventArgs : EventArgs + public struct DataReceivedEventArgs { - /// - /// Returns an instance of this object from the pool. - /// - /// A new or recycled DataEventArgs object. - internal static DataReceivedEventArgs GetObject() - { - return new DataReceivedEventArgs(); - } - /// /// The bytes received from the client. /// - public MessageReader Message { get; private set; } + public readonly MessageReader Message; /// /// The the data was sent with. /// - public SendOption SendOption { get; private set; } - - public ushort ReliableId { get; private set; } - - /// - /// Private constructor for object pool. - /// - DataReceivedEventArgs() - { - - } - - /// - /// Sets the members of the arguments. - /// - /// The bytes received. - /// The send option used to send the data. - internal void Set(MessageReader msg, SendOption sendOption, ushort reliableId) + public readonly SendOption SendOption; + + public DataReceivedEventArgs(MessageReader msg, SendOption sendOption) { this.Message = msg; this.SendOption = sendOption; - this.ReliableId = reliableId; } } } diff --git a/Hazel/Hazel.csproj b/Hazel/Hazel.csproj index b8027be..3cdfc7b 100644 --- a/Hazel/Hazel.csproj +++ b/Hazel/Hazel.csproj @@ -70,6 +70,9 @@ + + + diff --git a/Hazel/MessageReader.cs b/Hazel/MessageReader.cs index f7d0d76..8ac01bf 100644 --- a/Hazel/MessageReader.cs +++ b/Hazel/MessageReader.cs @@ -165,6 +165,16 @@ namespace Hazel return output; } + public uint ReadUInt32() + { + uint output = this.FastByte() + | (uint)this.FastByte() << 8 + | (uint)this.FastByte() << 16 + | (uint)this.FastByte() << 24; + + return output; + } + public int ReadInt32() { int output = this.FastByte() diff --git a/Hazel/MessageWriter.cs b/Hazel/MessageWriter.cs index bbe12c2..6f0c7b3 100644 --- a/Hazel/MessageWriter.cs +++ b/Hazel/MessageWriter.cs @@ -55,7 +55,12 @@ namespace Hazel System.Buffer.BlockCopy(this.Buffer, 1, output, 0, this.Length - 1); return output; } - + case SendOption.Tcp: + { + byte[] output = new byte[this.Length - 4]; + System.Buffer.BlockCopy(this.Buffer, 4, output, 0, this.Length - 4); + return output; + } } } @@ -120,6 +125,9 @@ namespace Hazel case SendOption.Reliable: this.Length = this.Position = 3; break; + case SendOption.Tcp: + this.Length = this.Position = 4; + break; } } @@ -183,6 +191,15 @@ namespace Hazel if (this.Position > this.Length) this.Length = this.Position; } + public void Write(uint value) + { + this.Buffer[this.Position++] = (byte)value; + this.Buffer[this.Position++] = (byte)(value >> 8); + this.Buffer[this.Position++] = (byte)(value >> 16); + this.Buffer[this.Position++] = (byte)(value >> 24); + if (this.Position > this.Length) this.Length = this.Position; + } + public void Write(int value) { this.Buffer[this.Position++] = (byte)value; diff --git a/Hazel/NetworkConnection.cs b/Hazel/NetworkConnection.cs index 01d13c0..8e7bd7e 100644 --- a/Hazel/NetworkConnection.cs +++ b/Hazel/NetworkConnection.cs @@ -39,5 +39,38 @@ namespace Hazel return BitConverter.ToInt64(bytes, bytes.Length - 8); } } + + /// + /// Called when the socket has been disconnected at the remote host. + /// + /// The exception if one was the cause. + public override void Disconnect(string reason) + { + this.Disconnect(reason, false); + } + + protected void Disconnect(string reason, bool skipSendDisconnect) + { + bool invoke = false; + lock (this) + { + if (this._state == ConnectionState.Connected) + { + this._state = skipSendDisconnect ? ConnectionState.NotConnected : ConnectionState.Disconnecting; + invoke = true; + } + } + + if (invoke) + { + try + { + InvokeDisconnected(reason); + } + catch { } + } + + this.Dispose(); + } } } diff --git a/Hazel/NewConnectionEventArgs.cs b/Hazel/NewConnectionEventArgs.cs index 64baad5..3c7ea9c 100644 --- a/Hazel/NewConnectionEventArgs.cs +++ b/Hazel/NewConnectionEventArgs.cs @@ -1,58 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Hazel +namespace Hazel { - /// - /// Event arguments for the event. - /// - /// - /// - /// This contains the new connection for the client that connection and is passed to subscribers of the - /// event. - /// - /// - /// - /// - public class NewConnectionEventArgs : EventArgs + public struct NewConnectionEventArgs { /// - /// Returns an instance of this object from the pool. - /// - /// A new or recycled NewConnectionEventArgs object. - internal static NewConnectionEventArgs GetObject() - { - return new NewConnectionEventArgs(); - } - - /// - /// The data received from the client in the handshake. - /// - public MessageReader HandshakeData { get; private set; } - - /// - /// The to the new client. + /// The data received from the client in the handshake. /// - public Connection Connection { get; private set; } + public readonly MessageReader HandshakeData; /// - /// Private constructor for object pool. + /// The to the new client. /// - NewConnectionEventArgs() - { + public readonly Connection Connection; - } - - /// - /// Sets the members of the arguments. - /// - /// The bytes that were received in the handshake. - /// The new connection - internal void Set(MessageReader msg, Connection connection) + public NewConnectionEventArgs(MessageReader handshakeData, Connection connection) { - this.HandshakeData = msg; + this.HandshakeData = handshakeData; this.Connection = connection; } } diff --git a/Hazel/SendOption.cs b/Hazel/SendOption.cs index c2ffb22..23d92cc 100644 --- a/Hazel/SendOption.cs +++ b/Hazel/SendOption.cs @@ -31,5 +31,7 @@ namespace Hazel /// a larger number of protocol bytes and can be slower than unreliable delivery. /// Reliable = 1, + + Tcp = 2, } } diff --git a/Hazel/Tcp/StateObject.cs b/Hazel/Tcp/StateObject.cs new file mode 100644 index 0000000..bee3d66 --- /dev/null +++ b/Hazel/Tcp/StateObject.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Hazel.Tcp +{ + /// + /// Represents the state of the current receive operation for TCP connections. + /// + struct StateObject + { + /// + /// The buffer we're receiving. + /// + internal MessageReader message; + + /// + /// The total number of bytes received so far. + /// + internal int totalBytesReceived; + + /// + /// The callback to invoke once the buffer has been filled. + /// + internal Action callback; + + internal readonly int ExpectedSize; + + /// + /// Creates a StateObject with the specified length. + /// + /// The number of bytes expected to be received. + /// The callback to invoke once data has been received. + internal StateObject(int length, Action callback) + { + this.message = MessageReader.GetSized(ushort.MaxValue); + this.totalBytesReceived = 0; + this.callback = callback; + this.ExpectedSize = length; + } + } +} \ No newline at end of file diff --git a/Hazel/Tcp/TcpConnection.cs b/Hazel/Tcp/TcpConnection.cs new file mode 100644 index 0000000..b2ed7ee --- /dev/null +++ b/Hazel/Tcp/TcpConnection.cs @@ -0,0 +1,310 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Text; + +namespace Hazel.Tcp +{ + /// + /// Represents a connection that uses the TCP protocol. + /// + /// + public sealed class TcpConnection : NetworkConnection + { + /// + /// The socket we're managing. + /// + Socket socket; + + /// + /// Creates a TcpConnection from a given TCP Socket. + /// + /// The TCP socket to wrap. + internal TcpConnection(Socket socket) + { + //Check it's a TCP socket + if (socket.ProtocolType != System.Net.Sockets.ProtocolType.Tcp) + throw new ArgumentException("A TcpConnection requires a TCP socket."); + + this.EndPoint = (IPEndPoint)socket.RemoteEndPoint; + this.RemoteEndPoint = socket.RemoteEndPoint; + + this.socket = socket; + this.socket.NoDelay = true; + + State = ConnectionState.Connected; + } + + /// + /// Creates a new TCP connection. + /// + /// A to connect to. + public TcpConnection(IPEndPoint remoteEndPoint, IPMode ipMode = IPMode.IPv4) + { + if (State != ConnectionState.NotConnected) + throw new InvalidOperationException("Cannot connect as the Connection is already connected."); + + this.EndPoint = remoteEndPoint; + this.RemoteEndPoint = remoteEndPoint; + this.IPMode = ipMode; + + //Create a socket + if (ipMode == IPMode.IPv4) + socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp); + else + { + if (!Socket.OSSupportsIPv6) + throw new InvalidOperationException("IPV6 not supported!"); + + socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp); + socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false); + } + + socket.NoDelay = true; + } + + /// + public override void Connect(byte[] bytes = null, int timeout = 5000) + { + //Connect + State = ConnectionState.Connecting; + + try + { + IAsyncResult result = socket.BeginConnect(RemoteEndPoint, null, null); + + result.AsyncWaitHandle.WaitOne(timeout); + + socket.EndConnect(result); + } + catch (Exception e) + { + throw new HazelException("Could not connect as an exception occured.", e); + } + + //Start receiving data + try + { + ListenForData(InvokeAndListen); + } + catch (Exception e) + { + throw new HazelException("An exception occured while initiating the first receive operation.", e); + } + + //Set connected + State = ConnectionState.Connected; + + //Send handshake + byte[] actualBytes; + if (bytes == null) + { + actualBytes = new byte[1]; + } + else + { + actualBytes = new byte[bytes.Length + 1]; + Buffer.BlockCopy(bytes, 0, actualBytes, 1, bytes.Length); + } + + SendBytes(actualBytes); + } + + public override void ConnectAsync(byte[] bytes = null, int timeout = 5000) + { + throw new NotImplementedException("I don't need this, so I didn't make it."); + } + + public override void Send(MessageWriter msg) + { + if (msg.SendOption != SendOption.Tcp) throw new InvalidOperationException("Sorry, no can do, holmes."); + + if (State != ConnectionState.Connected) + throw new InvalidOperationException("Could not send data as this Connection is not connected. Did you disconnect?"); + + var fullBytes = PrependLengthHeader(msg.Buffer, msg.Length); + + try + { + socket.BeginSend(fullBytes, 0, fullBytes.Length, SocketFlags.None, null, null); + } + catch (Exception e) + { + Disconnect("Could not send data as an occured: " + e.Message); + } + + Statistics.LogFragmentedSend(msg.Length, fullBytes.Length); + } + + /// + /// + /// + /// + /// The sendOption parameter is ignored by the TcpConnection as TCP only supports FragmentedReliable + /// communication, specifying anything else will have no effect. + /// + /// + public override void SendBytes(byte[] bytes, SendOption sendOption = SendOption.Tcp) + { + if (State != ConnectionState.Connected) + throw new InvalidOperationException("Could not send data as this Connection is not connected. Did you disconnect?"); + + var fullBytes = PrependLengthHeader(bytes); + + try + { + socket.BeginSend(fullBytes, 0, fullBytes.Length, SocketFlags.None, null, null); + } + catch (Exception e) + { + Disconnect("Could not send data as an occured: " + e.Message); + } + + Statistics.LogFragmentedSend(bytes.Length, fullBytes.Length); + } + + /// + /// Starts waiting for a first handshake packet to be received. + /// + /// The callback to invoke when the handshake has been received. + internal void StartWaitingForHandshake(Action callback) + { + this.State = ConnectionState.Connected; + + try + { + ListenForData( + delegate (MessageReader msg) + { + ListenForData(InvokeAndListen); + + //Remove version byte + msg.Offset = 1; + msg.Length -= 1; + msg.Position = 0; + + callback.Invoke(msg); + } + ); + } + catch (Exception e) + { + Disconnect("An exception occured while initiating the first receive operation: " + e.Message); + } + } + + private void InvokeAndListen(MessageReader msg) + { + this.ListenForData(InvokeAndListen); + + try + { + this.InvokeDataReceived(msg, SendOption.Tcp); + } + catch { } + } + + private void ListenForData(Action callback) + { + if (State == ConnectionState.Disconnecting || State == ConnectionState.NotConnected) + throw new HazelException("Not connected"); + + var msg = MessageReader.GetSized(ushort.MaxValue); + socket.BeginReceive(msg.Buffer, 0, 4, SocketFlags.None, o => HeaderReadCallback(callback, o), msg); + } + + private void HeaderReadCallback(Action callback, IAsyncResult result) + { + int bytesRead = socket.EndReceive(result); + var msg = (MessageReader)result.AsyncState; + + Statistics.LogFragmentedReceive(0, bytesRead); + + // TODO: Could possibly fragment here... + msg.Length = GetLengthFromBytes(msg.Buffer); + + socket.BeginReceive(msg.Buffer, 0, msg.Length, SocketFlags.None, o => BodyReadCallback(callback, o), msg); + } + + private void BodyReadCallback(Action callback, IAsyncResult result) + { + int bytesRead = socket.EndReceive(result); + var msg = (MessageReader)result.AsyncState; + msg.Position += bytesRead; + + Statistics.LogFragmentedReceive(bytesRead, 0); + + if (msg.Position < bytesRead) + { + socket.BeginReceive(msg.Buffer, msg.Position, msg.Length - msg.Position, SocketFlags.None, o => BodyReadCallback(callback, o), msg); + } + else + { + msg.Position = 0; + try + { + callback(msg); + } + catch { } + } + } + + protected override void SendDisconnect() + { + // Just dispose the connection, it's inherent to TCP. + } + + /// + /// Appends the length header to the bytes. + /// + /// The source bytes. + /// The new bytes. + private static byte[] PrependLengthHeader(byte[] bytes, int length = -1) + { + length = length > -1 ? length : bytes.Length; + + byte[] fullBytes = new byte[length + 4]; + Buffer.BlockCopy(bytes, 0, fullBytes, 4, length); + + fullBytes[0] = (byte)(length >> 24); + fullBytes[1] = (byte)(length >> 16); + fullBytes[2] = (byte)(length >> 8); + fullBytes[3] = (byte)length; + + return fullBytes; + } + + /// + /// Returns the length from a length header. + /// + /// The bytes received. + /// The number of bytes. + static int GetLengthFromBytes(byte[] bytes) + { + if (bytes.Length < 4) + throw new IndexOutOfRangeException("Not enough bytes passed to calculate length."); + + return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]; + } + + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + lock (this) + { + State = ConnectionState.NotConnected; + + if (socket.Connected) + socket.Shutdown(SocketShutdown.Send); + socket.Close(); + } + } + + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/Hazel/Tcp/TcpConnectionListener.cs b/Hazel/Tcp/TcpConnectionListener.cs new file mode 100644 index 0000000..4b9fcd2 --- /dev/null +++ b/Hazel/Tcp/TcpConnectionListener.cs @@ -0,0 +1,92 @@ +using System; +using System.Net; +using System.Net.Sockets; + +namespace Hazel.Tcp +{ + public sealed class TcpConnectionListener : NetworkConnectionListener + { + private Socket listener; + + /// + /// Creates a new TcpConnectionListener for the given , port and . + /// + /// The end point to listen on. + public TcpConnectionListener(IPEndPoint endPoint, IPMode ipMode = IPMode.IPv4) + { + this.EndPoint = endPoint; + this.IPMode = ipMode; + + if (this.IPMode == IPMode.IPv4) + this.listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + else + { + if (!Socket.OSSupportsIPv6) + throw new InvalidOperationException("IPV6 not supported!"); + + this.listener = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp); + this.listener.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false); + } + } + + /// + public override void Start() + { + try + { + listener.Bind(EndPoint); + listener.Listen(1000); + + listener.BeginAccept(AcceptConnection, null); + } + catch (SocketException e) + { + throw new HazelException("Could not start listening as a SocketException occured", e); + } + } + + /// + /// Called when a new connection has been accepted by the listener. + /// + /// The asyncronous operation's result. + void AcceptConnection(IAsyncResult result) + { + //Accept Tcp socket + Socket tcpSocket; + try + { + tcpSocket = listener.EndAccept(result); + } + catch (ObjectDisposedException) + { + //If the socket's been disposed then we can just end there. + return; + } + + //Start listening for the next connection + listener.BeginAccept(AcceptConnection, null); + + //Sort the event out + TcpConnection tcpConnection = new TcpConnection(tcpSocket); + + //Wait for handshake + tcpConnection.StartWaitingForHandshake( + delegate (MessageReader msg) + { + InvokeNewConnection(msg, tcpConnection); + } + ); + } + + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + listener.Dispose(); + } + + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/Hazel/Udp/UdpClientConnection.cs b/Hazel/Udp/UdpClientConnection.cs index 4dd101e..3dd3ef9 100644 --- a/Hazel/Udp/UdpClientConnection.cs +++ b/Hazel/Udp/UdpClientConnection.cs @@ -43,7 +43,7 @@ namespace Hazel.Udp else { if (!Socket.OSSupportsIPv6) - throw new HazelException("IPV6 not supported!"); + throw new InvalidOperationException("IPV6 not supported!"); socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp); socket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false); //TODO these lines shouldn't be needed anymore diff --git a/Hazel/Udp/UdpConnection.Reliable.cs b/Hazel/Udp/UdpConnection.Reliable.cs index 0e1182e..b5e0b48 100644 --- a/Hazel/Udp/UdpConnection.Reliable.cs +++ b/Hazel/Udp/UdpConnection.Reliable.cs @@ -311,7 +311,7 @@ namespace Hazel.Udp ushort id; if (ProcessReliableReceive(message.Buffer, 1, out id)) { - InvokeDataReceived(SendOption.Reliable, message, 3, bytesReceived, id); + InvokeDataReceived(SendOption.Reliable, message, 3, bytesReceived); } else { diff --git a/Hazel/Udp/UdpConnection.cs b/Hazel/Udp/UdpConnection.cs index 7c1b592..ddac37e 100644 --- a/Hazel/Udp/UdpConnection.cs +++ b/Hazel/Udp/UdpConnection.cs @@ -78,38 +78,7 @@ namespace Hazel.Udp //Add header information and send HandleSend(bytes, (byte)sendOption); } - - /// - /// Sends a number of bytes to the end point of the connection using the specified . - /// - /// The bytes of the message to send. - /// - /// - /// The option specifying how the message should be sent. - /// - /// - /// - /// The sendOptions parameter is only a request to use those options and the actual method used to send the - /// data is up to the implementation. There are circumstances where this parameter may be ignored but in - /// general any implementer should aim to always follow the user's request. - /// - /// - public override void SendBytes(byte[] bytes, int offset, int length, SendOption sendOption = SendOption.None) - { - switch (sendOption) - { - //Handle reliable header and hellos - case SendOption.Reliable: - ReliableSend((byte)sendOption, bytes, offset, length); - break; - - //Treat all else as unreliable - default: - UnreliableSend((byte)sendOption, bytes, offset, length); - break; - } - } - + /// /// Handles the reliable/fragmented sending from this connection. /// @@ -172,7 +141,7 @@ namespace Hazel.Udp //Treat everything else as unreliable default: - InvokeDataReceived(SendOption.None, message, 1, bytesReceived, 0); + InvokeDataReceived(SendOption.None, message, 1, bytesReceived); Statistics.LogUnreliableReceive(message.Length - 1, message.Length); break; } @@ -217,13 +186,13 @@ namespace Hazel.Udp /// The send option the message was received with. /// The buffer received. /// The offset of data in the buffer. - void InvokeDataReceived(SendOption sendOption, MessageReader buffer, int dataOffset, int bytesReceived, ushort reliableId) + void InvokeDataReceived(SendOption sendOption, MessageReader buffer, int dataOffset, int bytesReceived) { buffer.Offset = dataOffset; buffer.Length = bytesReceived - dataOffset; buffer.Position = 0; - InvokeDataReceived(buffer, sendOption, reliableId); + InvokeDataReceived(buffer, sendOption); } /// @@ -246,40 +215,7 @@ namespace Hazel.Udp HandleSend(actualBytes, (byte)UdpSendOption.Hello, acknowledgeCallback); } - - /// - /// Called when the socket has been disconnected at the remote host. - /// - /// The exception if one was the cause. - public override void Disconnect(string reason) - { - this.Disconnect(reason, false); - } - - protected void Disconnect(string reason, bool skipSendDisconnect) - { - bool invoke = false; - lock (this) - { - if (this._state == ConnectionState.Connected) - { - this._state = skipSendDisconnect ? ConnectionState.NotConnected : ConnectionState.Disconnecting; - invoke = true; - } - } - - if (invoke) - { - try - { - InvokeDisconnected(reason); - } - catch { } - } - - this.Dispose(); - } - + /// protected override void Dispose(bool disposing) { diff --git a/Hazel/Udp/UdpServerConnection.cs b/Hazel/Udp/UdpServerConnection.cs index a9f63c4..0cdf03e 100644 --- a/Hazel/Udp/UdpServerConnection.cs +++ b/Hazel/Udp/UdpServerConnection.cs @@ -59,7 +59,7 @@ namespace Hazel.Udp /// public override void Connect(byte[] bytes = null, int timeout = 5000) { - throw new HazelException("Cannot manually connect a UdpServerConnection, did you mean to use UdpClientConnection?"); + throw new InvalidOperationException("Cannot manually connect a UdpServerConnection, did you mean to use UdpClientConnection?"); } /// @@ -68,7 +68,7 @@ namespace Hazel.Udp /// public override void ConnectAsync(byte[] bytes = null, int timeout = 5000) { - throw new HazelException("Cannot manually connect a UdpServerConnection, did you mean to use UdpClientConnection?"); + throw new InvalidOperationException("Cannot manually connect a UdpServerConnection, did you mean to use UdpClientConnection?"); } -- 2.39.5