/// <example>
/// <code language="C#" source="DocInclude/TcpClientExample.cs"/>
/// </example>
- public Action<DataReceivedEventArgs> DataReceived;
+ public event Action<DataReceivedEventArgs> DataReceived;
public int TestLagMs = -1;
/// </para>
/// </remarks>
public abstract void SendBytes(byte[] bytes, SendOption sendOption = SendOption.None);
-
- /// <summary>
- /// Sends a number of bytes to the end point of the connection using the specified <see cref="SendOption"/>.
- /// </summary>
- /// <param name="bytes">The bytes of the message to send.</param>
- /// <param name="offset"></param>
- /// <param name="length"></param>
- /// <param name="sendOption">The option specifying how the message should be sent.</param>
- /// <remarks>
- /// <include file="DocInclude/common.xml" path="docs/item[@name='Connection_SendBytes_General']/*" />
- /// <para>
- /// 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.
- /// </para>
- /// </remarks>
- public abstract void SendBytes(byte[] bytes, int offset, int length, SendOption sendOption = SendOption.None);
-
+
/// <summary>
/// Connects the connection to a server and begins listening.
/// </summary>
/// received. The bytes and the send option that the message was sent with should be passed in to give to the
/// subscribers.
/// </remarks>
- 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<DataReceivedEventArgs> handler = DataReceived;
if (handler != null)
{
- DataReceivedEventArgs args = DataReceivedEventArgs.GetObject();
- args.Set(msg, sendOption, reliableId);
- handler.Invoke(args);
+ handler(new DataReceivedEventArgs(msg, sendOption));
}
else
{
/// <example>
/// <code language="C#" source="DocInclude/TcpListenerExample.cs"/>
/// </example>
- public Action<NewConnectionEventArgs> NewConnection;
+ public event Action<NewConnectionEventArgs> NewConnection;
/// <summary>
/// Makes this connection listener begin listening for connections.
Action<NewConnectionEventArgs> handler = NewConnection;
if (handler != null)
{
- NewConnectionEventArgs args = NewConnectionEventArgs.GetObject();
- args.Set(msg, connection);
- handler(args);
+ handler(new NewConnectionEventArgs(msg, connection));
}
else
{
namespace Hazel
{
- /// <summary>
- /// Event arguments for the <see cref="Connection.DataReceived"/> event.
- /// </summary>
- /// <remarks>
- /// <para>
- /// This contains information about messages received by a connection and is passed to subscribers of the
- /// <see cref="Connection.DataReceived">DataEvent</see>.
- /// </para>
- /// <include file="DocInclude/common.xml" path="docs/item[@name='Recyclable']/*" />
- /// </remarks>
- /// <threadsafety static="true" instance="true"/>
- public class DataReceivedEventArgs : EventArgs
+ public struct DataReceivedEventArgs
{
- /// <summary>
- /// Returns an instance of this object from the pool.
- /// </summary>
- /// <returns>A new or recycled DataEventArgs object.</returns>
- internal static DataReceivedEventArgs GetObject()
- {
- return new DataReceivedEventArgs();
- }
-
/// <summary>
/// The bytes received from the client.
/// </summary>
- public MessageReader Message { get; private set; }
+ public readonly MessageReader Message;
/// <summary>
/// The <see cref="SendOption"/> the data was sent with.
/// </summary>
- public SendOption SendOption { get; private set; }
-
- public ushort ReliableId { get; private set; }
-
- /// <summary>
- /// Private constructor for object pool.
- /// </summary>
- DataReceivedEventArgs()
- {
-
- }
-
- /// <summary>
- /// Sets the members of the arguments.
- /// </summary>
- /// <param name="bytes">The bytes received.</param>
- /// <param name="sendOption">The send option used to send the data.</param>
- 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;
}
}
}
<Compile Include="ObjectPool.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SendOption.cs" />
+ <Compile Include="Tcp\StateObject.cs" />
+ <Compile Include="Tcp\TcpConnection.cs" />
+ <Compile Include="Tcp\TcpConnectionListener.cs" />
<Compile Include="Udp\SendOptionInternal.cs" />
<Compile Include="ConnectionStatistics.cs" />
<Compile Include="Udp\UdpBroadcaster.cs" />
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()
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;
+ }
}
}
case SendOption.Reliable:
this.Length = this.Position = 3;
break;
+ case SendOption.Tcp:
+ this.Length = this.Position = 4;
+ break;
}
}
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;
return BitConverter.ToInt64(bytes, bytes.Length - 8);
}
}
+
+ /// <summary>
+ /// Called when the socket has been disconnected at the remote host.
+ /// </summary>
+ /// <param name="e">The exception if one was the cause.</param>
+ 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();
+ }
}
}
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace Hazel
+namespace Hazel
{
- /// <summary>
- /// Event arguments for the <see cref="ConnectionListener.NewConnection"/> event.
- /// </summary>
- /// <remarks>
- /// <para>
- /// This contains the new connection for the client that connection and is passed to subscribers of the
- /// <see cref="ConnectionListener.NewConnection"/> event.
- /// </para>
- /// <include file="DocInclude/common.xml" path="docs/item[@name='Recyclable']/*" />
- /// </remarks>
- /// <threadsafety static="true" instance="true"/>
- public class NewConnectionEventArgs : EventArgs
+ public struct NewConnectionEventArgs
{
/// <summary>
- /// Returns an instance of this object from the pool.
- /// </summary>
- /// <returns>A new or recycled NewConnectionEventArgs object.</returns>
- internal static NewConnectionEventArgs GetObject()
- {
- return new NewConnectionEventArgs();
- }
-
- /// <summary>
- /// The data received from the client in the handshake.
- /// </summary>
- public MessageReader HandshakeData { get; private set; }
-
- /// <summary>
- /// The <see cref="Connection"/> to the new client.
+ /// The data received from the client in the handshake.
/// </summary>
- public Connection Connection { get; private set; }
+ public readonly MessageReader HandshakeData;
/// <summary>
- /// Private constructor for object pool.
+ /// The <see cref="Connection"/> to the new client.
/// </summary>
- NewConnectionEventArgs()
- {
+ public readonly Connection Connection;
- }
-
- /// <summary>
- /// Sets the members of the arguments.
- /// </summary>
- /// <param name="msg">The bytes that were received in the handshake.</param>
- /// <param name="connection">The new connection</param>
- internal void Set(MessageReader msg, Connection connection)
+ public NewConnectionEventArgs(MessageReader handshakeData, Connection connection)
{
- this.HandshakeData = msg;
+ this.HandshakeData = handshakeData;
this.Connection = connection;
}
}
/// a larger number of protocol bytes and can be slower than unreliable delivery.
/// </remarks>
Reliable = 1,
+
+ Tcp = 2,
}
}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Hazel.Tcp
+{
+ /// <summary>
+ /// Represents the state of the current receive operation for TCP connections.
+ /// </summary>
+ struct StateObject
+ {
+ /// <summary>
+ /// The buffer we're receiving.
+ /// </summary>
+ internal MessageReader message;
+
+ /// <summary>
+ /// The total number of bytes received so far.
+ /// </summary>
+ internal int totalBytesReceived;
+
+ /// <summary>
+ /// The callback to invoke once the buffer has been filled.
+ /// </summary>
+ internal Action<MessageReader> callback;
+
+ internal readonly int ExpectedSize;
+
+ /// <summary>
+ /// Creates a StateObject with the specified length.
+ /// </summary>
+ /// <param name="length">The number of bytes expected to be received.</param>
+ /// <param name="callback">The callback to invoke once data has been received.</param>
+ internal StateObject(int length, Action<MessageReader> callback)
+ {
+ this.message = MessageReader.GetSized(ushort.MaxValue);
+ this.totalBytesReceived = 0;
+ this.callback = callback;
+ this.ExpectedSize = length;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+
+namespace Hazel.Tcp
+{
+ /// <summary>
+ /// Represents a connection that uses the TCP protocol.
+ /// </summary>
+ /// <inheritdoc />
+ public sealed class TcpConnection : NetworkConnection
+ {
+ /// <summary>
+ /// The socket we're managing.
+ /// </summary>
+ Socket socket;
+
+ /// <summary>
+ /// Creates a TcpConnection from a given TCP Socket.
+ /// </summary>
+ /// <param name="socket">The TCP socket to wrap.</param>
+ 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;
+ }
+
+ /// <summary>
+ /// Creates a new TCP connection.
+ /// </summary>
+ /// <param name="remoteEndPoint">A <see cref="NetworkEndPoint"/> to connect to.</param>
+ 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;
+ }
+
+ /// <inheritdoc />
+ 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);
+ }
+
+ /// <inheritdoc/>
+ /// <remarks>
+ /// <include file="DocInclude/common.xml" path="docs/item[@name='Connection_SendBytes_General']/*" />
+ /// <para>
+ /// The sendOption parameter is ignored by the TcpConnection as TCP only supports FragmentedReliable
+ /// communication, specifying anything else will have no effect.
+ /// </para>
+ /// </remarks>
+ 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);
+ }
+
+ /// <summary>
+ /// Starts waiting for a first handshake packet to be received.
+ /// </summary>
+ /// <param name="callback">The callback to invoke when the handshake has been received.</param>
+ internal void StartWaitingForHandshake(Action<MessageReader> 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<MessageReader> 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<MessageReader> 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<MessageReader> 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.
+ }
+
+ /// <summary>
+ /// Appends the length header to the bytes.
+ /// </summary>
+ /// <param name="bytes">The source bytes.</param>
+ /// <returns>The new bytes.</returns>
+ 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;
+ }
+
+ /// <summary>
+ /// Returns the length from a length header.
+ /// </summary>
+ /// <param name="bytes">The bytes received.</param>
+ /// <returns>The number of bytes.</returns>
+ 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];
+ }
+
+ /// <inheritdoc />
+ 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
--- /dev/null
+using System;
+using System.Net;
+using System.Net.Sockets;
+
+namespace Hazel.Tcp
+{
+ public sealed class TcpConnectionListener : NetworkConnectionListener
+ {
+ private Socket listener;
+
+ /// <summary>
+ /// Creates a new TcpConnectionListener for the given <see cref="IPAddress"/>, port and <see cref="IPMode"/>.
+ /// </summary>
+ /// <param name="endPoint">The end point to listen on.</param>
+ 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);
+ }
+ }
+
+ /// <inheritdoc />
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// Called when a new connection has been accepted by the listener.
+ /// </summary>
+ /// <param name="result">The asyncronous operation's result.</param>
+ 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);
+ }
+ );
+ }
+
+ /// <inheritdoc/>
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ listener.Dispose();
+ }
+
+ base.Dispose(disposing);
+ }
+ }
+}
\ No newline at end of file
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
ushort id;
if (ProcessReliableReceive(message.Buffer, 1, out id))
{
- InvokeDataReceived(SendOption.Reliable, message, 3, bytesReceived, id);
+ InvokeDataReceived(SendOption.Reliable, message, 3, bytesReceived);
}
else
{
//Add header information and send
HandleSend(bytes, (byte)sendOption);
}
-
- /// <summary>
- /// Sends a number of bytes to the end point of the connection using the specified <see cref="SendOption"/>.
- /// </summary>
- /// <param name="bytes">The bytes of the message to send.</param>
- /// <param name="offset"></param>
- /// <param name="length"></param>
- /// <param name="sendOption">The option specifying how the message should be sent.</param>
- /// <remarks>
- /// <include file="DocInclude/common.xml" path="docs/item[@name='Connection_SendBytes_General']/*" />
- /// <para>
- /// 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.
- /// </para>
- /// </remarks>
- 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;
- }
- }
-
+
/// <summary>
/// Handles the reliable/fragmented sending from this connection.
/// </summary>
//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;
}
/// <param name="sendOption">The send option the message was received with.</param>
/// <param name="buffer">The buffer received.</param>
/// <param name="dataOffset">The offset of data in the buffer.</param>
- 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);
}
/// <summary>
HandleSend(actualBytes, (byte)UdpSendOption.Hello, acknowledgeCallback);
}
-
- /// <summary>
- /// Called when the socket has been disconnected at the remote host.
- /// </summary>
- /// <param name="e">The exception if one was the cause.</param>
- 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();
- }
-
+
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
/// </remarks>
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?");
}
/// <inheritdoc />
/// </remarks>
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?");
}