]> git.deb.at Git - rhonda/impostor.hazel.git/commitdiff
Update to VS2017 and remove TCP and add UDP Broadcaster
authorForest <chocozilla@gmail.com>
Mon, 16 Jul 2018 19:12:53 +0000 (12:12 -0700)
committerForest <chocozilla@gmail.com>
Mon, 16 Jul 2018 19:12:53 +0000 (12:12 -0700)
.gitignore
Hazel.UnitTests/BroadcastTests.cs [new file with mode: 0644]
Hazel.UnitTests/Hazel.UnitTests.csproj
Hazel.UnitTests/TcpConnectionTests.cs [deleted file]
Hazel/Hazel.csproj
Hazel/Tcp/StateObject.cs [deleted file]
Hazel/Tcp/TcpConnection.cs [deleted file]
Hazel/Tcp/TcpConnectionListener.cs [deleted file]
Hazel/Udp/UdpBroadcastListener.cs [new file with mode: 0644]
Hazel/Udp/UdpBroadcaster.cs [new file with mode: 0644]

index 360e580b456dd55bc4c9457c2e0787e9eeced011..9bf6cfbd16d55ec644004ba745fb85591b6d3a59 100644 (file)
@@ -5,6 +5,7 @@
 *.suo
 *.user
 *.sln.docstates
+.vs/
 
 # Build results
 [Dd]ebug/
diff --git a/Hazel.UnitTests/BroadcastTests.cs b/Hazel.UnitTests/BroadcastTests.cs
new file mode 100644 (file)
index 0000000..53b3139
--- /dev/null
@@ -0,0 +1,39 @@
+using Hazel.Udp;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Linq;
+using System.Net;
+using System.Threading;
+
+namespace Hazel.UnitTests
+{
+    [TestClass]
+    public class BroadcastTests
+    {
+        [TestMethod]
+        public void CanStart()
+        {
+            const string TestData = "pwerowerower";
+
+            using (UdpBroadcaster caster = new UdpBroadcaster(47777))
+            using (UdpBroadcastListener listener = new UdpBroadcastListener(47777))
+            {
+                listener.StartListen();
+
+                caster.SetData(TestData);
+
+                caster.Broadcast();
+                Thread.Sleep(1000);
+
+                var pkt = listener.GetPackets();
+                foreach (var p in pkt)
+                {
+                    Console.WriteLine($"{p.Data} {p.Sender}");
+                    Assert.AreEqual(TestData, p.Data);
+                }
+
+                Assert.AreEqual(1, pkt.Length);
+            }
+        }
+    }
+}
index a380240f9892d55aabd604b072c6a078d2694c64..73dbb50833794732a3221e433600eceacdf5676a 100644 (file)
     </Otherwise>
   </Choose>
   <ItemGroup>
+    <Compile Include="BroadcastTests.cs" />
     <Compile Include="StatisticsTests.cs" />
     <Compile Include="TestHelper.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="TcpConnectionTests.cs" />
     <Compile Include="UdpConnectionTests.cs" />
   </ItemGroup>
   <ItemGroup>
diff --git a/Hazel.UnitTests/TcpConnectionTests.cs b/Hazel.UnitTests/TcpConnectionTests.cs
deleted file mode 100644 (file)
index 9ef0772..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-using System;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System.Net;
-using System.Threading;
-
-using Hazel.Tcp;
-using System.Linq;
-
-namespace Hazel.UnitTests
-{
-    [TestClass]
-    public class TcpConnectionTests
-    {
-        /// <summary>
-        ///     Tests the fields on TcpConnection.
-        /// </summary>
-        [TestMethod]
-        public void TcpFieldTest()
-        {
-            NetworkEndPoint ep = new NetworkEndPoint(IPAddress.Loopback, 4296);
-
-            using (TcpConnectionListener listener = new TcpConnectionListener(new NetworkEndPoint(IPAddress.Any, 4296)))
-            using (TcpConnection connection = new TcpConnection(ep))
-            {
-                listener.Start();
-
-                connection.Connect();
-
-                //Connection fields
-                Assert.AreEqual(ep, connection.EndPoint);
-
-                //TcpConnection fields
-                Assert.AreEqual(new IPEndPoint(IPAddress.Loopback, 4296), connection.RemoteEndPoint);
-                Assert.AreEqual(1, connection.Statistics.DataBytesSent);
-                Assert.AreEqual(0, connection.Statistics.DataBytesReceived);
-            }
-        }
-
-        [TestMethod]
-        public void TcpHandshakeTest()
-        {
-            using (TcpConnectionListener listener = new TcpConnectionListener(new NetworkEndPoint(IPAddress.Any, 4296, IPMode.IPv4)))
-            using (TcpConnection connection = new TcpConnection(new NetworkEndPoint(IPAddress.Loopback, 4296, IPMode.IPv4)))
-            {
-                listener.Start();
-
-                listener.NewConnection += delegate (object sender, NewConnectionEventArgs e)
-                {
-                    Assert.IsTrue(Enumerable.SequenceEqual(e.HandshakeData, new byte[] { 1, 2, 3, 4, 5, 6 }));
-                };
-
-                connection.Connect(new byte[] { 1, 2, 3, 4, 5, 6 });
-            }
-        }
-
-        /// <summary>
-        ///     Tests IPv4 connectivity.
-        /// </summary>
-        [TestMethod]
-        public void TcpIPv4ConnectionTest()
-        {
-            using (TcpConnectionListener listener = new TcpConnectionListener(new NetworkEndPoint(IPAddress.Any, 4296, IPMode.IPv4)))
-            using (TcpConnection connection = new TcpConnection(new NetworkEndPoint(IPAddress.Loopback, 4296, IPMode.IPv4)))
-            {
-                listener.Start();
-
-                connection.Connect();
-            }
-        }
-
-        /// <summary>
-        ///     Tests dual mode connectivity.
-        /// </summary>
-        [TestMethod]
-        public void TcpIPv6ConnectionTest()
-        {
-            using (TcpConnectionListener listener = new TcpConnectionListener(new NetworkEndPoint(IPAddress.IPv6Any, 4296, IPMode.IPv6)))
-            {
-                listener.Start();
-
-                using (TcpConnection connection = new TcpConnection(new NetworkEndPoint(IPAddress.IPv6Loopback, 4296, IPMode.IPv6)))
-                {
-                    connection.Connect();
-                }
-            }
-        }
-
-        /// <summary>
-        ///     Tests sending and receiving on the TcpConnection.
-        /// </summary>
-        [TestMethod]
-        public void TcpServerToClientTest()
-        {
-            using (TcpConnectionListener listener = new TcpConnectionListener(new NetworkEndPoint(IPAddress.Any, 4296)))
-            using (TcpConnection connection = new TcpConnection(new NetworkEndPoint(IPAddress.Loopback, 4296)))
-            {
-                TestHelper.RunServerToClientTest(listener, connection, 10, SendOption.FragmentedReliable);
-            }
-        }
-
-        /// <summary>
-        ///     Tests sending and receiving on the TcpConnection.
-        /// </summary>
-        [TestMethod]
-        public void TcpClientToServerTest()
-        {
-            using (TcpConnectionListener listener = new TcpConnectionListener(new NetworkEndPoint(IPAddress.Any, 4296)))
-            using (TcpConnection connection = new TcpConnection(new NetworkEndPoint(IPAddress.Loopback, 4296)))
-            {
-                TestHelper.RunClientToServerTest(listener, connection, 10, SendOption.FragmentedReliable);
-            }
-        }
-
-        /// <summary>
-        ///     Tests disconnection from the client.
-        /// </summary>
-        [TestMethod]
-        public void ClientDisconnectTest()
-        {
-            using (TcpConnectionListener listener = new TcpConnectionListener(new NetworkEndPoint(IPAddress.Any, 4296)))
-            using (TcpConnection connection = new TcpConnection(new NetworkEndPoint(IPAddress.Loopback, 4296)))
-            {
-                TestHelper.RunClientDisconnectTest(listener, connection);
-            }
-        }
-
-        /// <summary>
-        ///     Tests disconnection from the server.
-        /// </summary>
-        [TestMethod]
-        public void ServerDisconnectTest()
-        {
-            using (TcpConnectionListener listener = new TcpConnectionListener(new NetworkEndPoint(IPAddress.Any, 4296)))
-            using (TcpConnection connection = new TcpConnection(new NetworkEndPoint(IPAddress.Loopback, 4296)))
-            {
-                TestHelper.RunServerDisconnectTest(listener, connection);
-            }
-        }
-    }
-}
index 5cf54e263748efa6ec5a6a55328d0c7c73ab5e03..98ec8dae4daff54846c37e43d90aa4f942a05249 100644 (file)
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="SendOption.cs" />
     <Compile Include="Udp\SendOptionInternal.cs" />
-    <Compile Include="Tcp\StateObject.cs" />
     <Compile Include="ConnectionStatistics.cs" />
-    <Compile Include="Tcp\TcpConnection.cs" />
-    <Compile Include="Tcp\TcpConnectionListener.cs" />
+    <Compile Include="Udp\UdpBroadcaster.cs" />
+    <Compile Include="Udp\UdpBroadcastListener.cs" />
     <Compile Include="Udp\UdpClientConnection.cs" />
     <Compile Include="Udp\UdpConnection.cs">
       <SubType>Code</SubType>
diff --git a/Hazel/Tcp/StateObject.cs b/Hazel/Tcp/StateObject.cs
deleted file mode 100644 (file)
index 8c4ac20..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-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 byte[] buffer;
-
-        /// <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<byte[]> callback;
-
-        /// <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<byte[]> callback)
-        {
-            this.buffer = new byte[length];
-            this.totalBytesReceived = 0;
-            this.callback = callback;
-        }
-    }
-}
diff --git a/Hazel/Tcp/TcpConnection.cs b/Hazel/Tcp/TcpConnection.cs
deleted file mode 100644 (file)
index 99d60c1..0000000
+++ /dev/null
@@ -1,413 +0,0 @@
-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>
-        ///     Lock for the socket.
-        /// </summary>
-        Object socketLock = new Object();
-
-        /// <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.");
-
-            lock (this.socketLock)
-            {
-                this.EndPoint = new NetworkEndPoint(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(NetworkEndPoint remoteEndPoint)
-        {
-            lock (socketLock)
-            {
-                if (State != ConnectionState.NotConnected)
-                    throw new InvalidOperationException("Cannot connect as the Connection is already connected.");
-
-                this.EndPoint = remoteEndPoint;
-                this.RemoteEndPoint = remoteEndPoint.EndPoint;
-                this.IPMode = remoteEndPoint.IPMode;
-
-                //Create a socket
-                if (remoteEndPoint.IPMode == IPMode.IPv4)
-                    socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
-                else
-                {
-                    if (!Socket.OSSupportsIPv6)
-                        throw new HazelException("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)
-        {
-            lock(socketLock)
-            {
-                //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
-                {
-                    StartWaitingForHeader(BodyReadCallback);
-                }
-                catch (Exception e)
-                {
-                    throw new HazelException("An exception occured while initiating the first receive operation.", e);
-                }
-
-                //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);
-                }
-                
-                //Set connected
-                State = ConnectionState.Connected;
-
-                SendBytes(actualBytes);
-            }
-        }
-
-        /// <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.FragmentedReliable)
-        {
-            //Get bytes for length
-            byte[] fullBytes = AppendLengthHeader(bytes);
-
-            //Write the bytes to the socket
-            lock (socketLock)
-            {
-                if (State != ConnectionState.Connected)
-                    throw new InvalidOperationException("Could not send data as this Connection is not connected. Did you disconnect?");
-            
-                try
-                {
-                    socket.BeginSend(fullBytes, 0, fullBytes.Length, SocketFlags.None, null, null);
-                }
-                catch (Exception e)
-                {
-                    HazelException he = new HazelException("Could not send data as an occured.", e);
-                    HandleDisconnect(he);
-                    throw he;
-                }
-            }
-
-            Statistics.LogFragmentedSend(bytes.Length, fullBytes.Length);
-        }
-
-        /// <summary>
-        ///     Called when a 4 byte header has been received.
-        /// </summary>
-        /// <param name="bytes">The 4 header bytes read.</param>
-        /// <param name="callback">The callback to invoke when the body has been received.</param>
-        void HeaderReadCallback(byte[] bytes, Action<byte[]> callback)
-        {
-            //Get length 
-            int length = GetLengthFromBytes(bytes);
-
-            //Begin receiving the body
-            try
-            {
-                StartWaitingForBytes(length, callback);
-            }
-            catch (Exception e)
-            {
-                HandleDisconnect(new HazelException("An exception occured while initiating a body receive operation.", e));
-            }
-        }
-
-        /// <summary>
-        ///     Callback for when a body has been read.
-        /// </summary>
-        /// <param name="bytes">The data bytes received by the connection.</param>
-        void BodyReadCallback(byte[] bytes)
-        {
-            //Begin receiving from the start
-            try
-            {
-                StartWaitingForHeader(BodyReadCallback);
-            }
-            catch (Exception e)
-            {
-                HandleDisconnect(new HazelException("An exception occured while initiating a header receive operation.", e));
-            }
-
-            Statistics.LogFragmentedReceive(bytes.Length, bytes.Length + 4);
-
-            //Fire DataReceived event
-            InvokeDataReceived(bytes, SendOption.FragmentedReliable);
-        }
-
-        /// <summary>
-        ///     Starts this connection receiving data.
-        /// </summary>
-        internal void StartReceiving()
-        {
-            try
-            {
-                StartWaitingForHeader(BodyReadCallback);
-            }
-            catch (Exception e)
-            {
-                HandleDisconnect(new HazelException("An exception occured while initiating the first receive operation.", e));
-            }
-        }
-
-        /// <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<byte[]> callback)
-        {
-            try
-            {
-                StartWaitingForHeader(
-                    delegate (byte[] bytes)
-                    {
-                        //Remove version byte
-                        byte[] dataBytes = new byte[bytes.Length - 1];
-                        Buffer.BlockCopy(bytes, 1, dataBytes, 0, bytes.Length - 1);
-
-                        callback.Invoke(dataBytes);
-                    }
-                );
-            }
-            catch (Exception e)
-            {
-                HandleDisconnect(new HazelException("An exception occured while initiating the first receive operation.", e));
-            }
-        }
-
-        /// <summary>
-        ///     Starts this connections waiting for the header.
-        /// </summary>
-        /// <param name="callback">The callback to invoke when the body has been read.</param>
-        void StartWaitingForHeader(Action<byte[]> callback)
-        {
-            StartWaitingForBytes(4, (bytes) => HeaderReadCallback(bytes, callback));
-        }
-
-        /// <summary>
-        ///     Waits for the specified amount of bytes to be received.
-        /// </summary>
-        /// <param name="length">The number of bytes to receive.</param>
-        /// <param name="callback">The callback </param>
-        void StartWaitingForBytes(int length, Action<byte[]> callback)
-        {
-            StateObject state = new StateObject(length, callback);
-
-            StartWaitingForChunk(state);
-        }
-
-        /// <summary>
-        ///     Waits for the next chunk of data from this socket.
-        /// </summary>
-        /// <param name="state">The StateObject for the receive operation.</param>
-        void StartWaitingForChunk(StateObject state)
-        {
-            lock (socketLock)
-            {
-                //Double check we've not disconnected then begin receiving
-                if (State == ConnectionState.Connected || State == ConnectionState.Connecting)
-                    socket.BeginReceive(state.buffer, state.totalBytesReceived, state.buffer.Length - state.totalBytesReceived, SocketFlags.None, ChunkReadCallback, state);
-            }
-        }
-
-        /// <summary>
-        ///     Called when a chunk has been read.
-        /// </summary>
-        /// <param name="result"></param>
-        void ChunkReadCallback(IAsyncResult result)
-        {
-            int bytesReceived;
-
-            //End the receive operation
-            try
-            {
-                lock (socketLock)
-                    bytesReceived = socket.EndReceive(result);
-            }
-            catch (ObjectDisposedException)
-            {
-                //If the socket's been disposed then we can just end there.
-                return;
-            }
-            catch (Exception e)
-            {
-                HandleDisconnect(new HazelException("An exception occured while completing a chunk read operation.", e));
-                return;
-            }
-
-            StateObject state = (StateObject)result.AsyncState;
-
-            state.totalBytesReceived += bytesReceived;      //TODO threading issues on state?
-
-            //Exit if receive nothing
-            if (bytesReceived == 0)
-            {
-                HandleDisconnect();
-                return;
-            }
-
-            //If we need to receive more then wait for more, else process it.
-            if (state.totalBytesReceived < state.buffer.Length)
-            {
-                try
-                {
-                    StartWaitingForChunk(state);
-                }
-                catch (Exception e)
-                {
-                    HandleDisconnect(new HazelException("An exception occured while initiating a chunk receive operation.", e));
-                    return;
-                }
-            }
-            else
-                state.callback.Invoke(state.buffer);
-        }
-
-        /// <summary>
-        ///     Called when the socket has been disconnected at the remote host.
-        /// </summary>
-        /// <param name="e">The exception if one was the cause.</param>
-        void HandleDisconnect(HazelException e = null)
-        {
-            bool invoke = false;
-
-            lock (socketLock)
-            {
-                //Only invoke the disconnected event if we're not already disconnecting
-                if (State == ConnectionState.Connected)
-                {
-                    State = ConnectionState.Disconnecting;
-                    invoke = true;
-                }
-            }
-
-            //Invoke event outide lock if need be
-            if (invoke)
-            {
-                InvokeDisconnected(e);
-
-                Dispose();
-            }
-        }
-
-        /// <summary>
-        ///     Appends the length header to the bytes.
-        /// </summary>
-        /// <param name="bytes">The source bytes.</param>
-        /// <returns>The new bytes.</returns>
-        static byte[] AppendLengthHeader(byte[] bytes)
-        {
-            byte[] fullBytes = new byte[bytes.Length + 4];
-
-            //Append length
-            fullBytes[0] = (byte)(((uint)bytes.Length >> 24) & 0xFF);
-            fullBytes[1] = (byte)(((uint)bytes.Length >> 16) & 0xFF);
-            fullBytes[2] = (byte)(((uint)bytes.Length >> 8) & 0xFF);
-            fullBytes[3] = (byte)(uint)bytes.Length;
-
-            //Add rest of bytes
-            Buffer.BlockCopy(bytes, 0, fullBytes, 4, bytes.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 (socketLock)
-                {
-                    State = ConnectionState.NotConnected;
-
-                    if (socket.Connected)
-                        socket.Shutdown(SocketShutdown.Send);
-                    socket.Close();
-                }
-            }
-
-            base.Dispose(disposing);
-        }
-    }
-}
diff --git a/Hazel/Tcp/TcpConnectionListener.cs b/Hazel/Tcp/TcpConnectionListener.cs
deleted file mode 100644 (file)
index 8374d20..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-using System.Net.Sockets;
-using System.Text;
-
-
-namespace Hazel.Tcp
-{
-    /// <summary>
-    ///     Listens for new TCP connections and creates TCPConnections for them.
-    /// </summary>
-    /// <inheritdoc />
-    public sealed class TcpConnectionListener : NetworkConnectionListener
-    {
-        /// <summary>
-        ///     The socket listening for connections.
-        /// </summary>
-        Socket listener;
-
-        /// <summary>
-        ///     Creates a new TcpConnectionListener for the given <see cref="IPAddress"/>, port and <see cref="IPMode"/>.
-        /// </summary>
-        /// <param name="IPAddress">The IPAddress to listen on.</param>
-        /// <param name="port">The port to listen on.</param>
-        /// <param name="mode">The <see cref="IPMode"/> to listen with.</param>
-        [Obsolete("Temporary constructor in beta only, use NetworkEndPoint constructor instead.")]
-        public TcpConnectionListener(IPAddress IPAddress, int port, IPMode mode = IPMode.IPv4)
-            : this (new NetworkEndPoint(IPAddress, port, mode))
-        {
-
-        }
-
-        /// <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(NetworkEndPoint endPoint)
-        {
-            this.EndPoint = endPoint.EndPoint;
-            this.IPMode = endPoint.IPMode;
-
-            if (endPoint.IPMode == IPMode.IPv4)
-                this.listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
-            else
-            {
-                if (!Socket.OSSupportsIPv6)
-                    throw new HazelException("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
-            {
-                lock (listener)
-                {
-                    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)
-        {
-            lock (listener)
-            {
-                //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(new AsyncCallback(AcceptConnection), null);
-
-                //Sort the event out
-                TcpConnection tcpConnection = new TcpConnection(tcpSocket);
-
-                //Wait for handshake
-                tcpConnection.StartWaitingForHandshake(
-                    delegate (byte[] bytes)
-                    {
-                        //Invoke
-                        InvokeNewConnection(bytes, tcpConnection);
-
-                        tcpConnection.StartReceiving();
-                    }
-                );
-            }
-        }
-
-        /// <inheritdoc/>
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing)
-            {
-                lock (listener)
-                    listener.Close();
-            }
-
-            base.Dispose(disposing);
-        }
-    }
-}
diff --git a/Hazel/Udp/UdpBroadcastListener.cs b/Hazel/Udp/UdpBroadcastListener.cs
new file mode 100644 (file)
index 0000000..a9b1828
--- /dev/null
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+
+namespace Hazel.Udp
+{
+    ///
+    public class BroadcastPacket
+    {
+        ///
+        public string Data;
+
+        ///
+        public DateTime ReceiveTime;
+        
+        ///
+        public IPEndPoint Sender;
+
+        ///
+        public BroadcastPacket(string data, IPEndPoint sender)
+        {
+            this.Data = data;
+            this.Sender = sender;
+            this.ReceiveTime = DateTime.Now;
+        }
+
+        public string GetAddress()
+        {
+            return this.Sender.Address.ToString();
+        }
+    }
+
+    ///
+    public class UdpBroadcastListener : IDisposable
+    {
+        private Socket socket;
+        private EndPoint endpoint;
+
+        private byte[] buffer = new byte[1024];
+
+        private List<BroadcastPacket> packets = new List<BroadcastPacket>();
+
+        ///
+        public UdpBroadcastListener(int port)
+        {
+            this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+            this.endpoint = new IPEndPoint(IPAddress.Any, port);
+            this.socket.Bind(this.endpoint);
+        }
+
+        ///
+        public void StartListen()
+        {
+            if (this.socket == null) return;
+            
+            try
+            {
+                EndPoint endpt = new IPEndPoint(IPAddress.Any, 0);
+                var result = this.socket.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref endpt, this.HandleData, null);
+                if (result.CompletedSynchronously)
+                {
+                    this.HandleData(result);
+                }
+            }
+            catch
+            {
+                this.Dispose();
+            }
+        }
+
+        ///
+        public void HandleData(IAsyncResult result)
+        {
+            int numBytes;
+            EndPoint endpt = new IPEndPoint(IPAddress.Any, 0);
+            try
+            {
+                numBytes = this.socket.EndReceiveFrom(result, ref endpt);
+            }
+            catch
+            {
+                this.Dispose();
+                return;
+            }
+
+            if (numBytes < 2) return;
+            if (buffer[0] != 4 || buffer[1] != 2) return;
+
+            IPEndPoint ipEnd = (IPEndPoint)endpt;
+            string data = ASCIIEncoding.ASCII.GetString(buffer, 2, numBytes - 2);
+            int dataHash = data.GetHashCode();
+
+            lock (packets)
+            {
+                bool found = false;
+                for (int i = 0; i < this.packets.Count; ++i)
+                {
+                    var pkt = this.packets[i];
+                    if (pkt.Data.GetHashCode() == dataHash
+                        && pkt.Sender.Equals(ipEnd))
+                    {
+                        this.packets[i].ReceiveTime = DateTime.Now;
+                        break;
+                    }
+                }
+
+                if (!found)
+                {
+                    this.packets.Add(new BroadcastPacket(data, ipEnd));
+                }
+            }
+
+            this.StartListen();
+        }
+
+        ///
+        public BroadcastPacket[] GetPackets()
+        {
+            lock (this.packets)
+            {
+                var output = this.packets.ToArray();
+                this.packets.Clear();
+                return output;
+            }
+        }
+
+        ///
+        public void Dispose()
+        {
+            if (this.socket != null)
+            {
+                this.socket.Close();
+                this.socket = null;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Hazel/Udp/UdpBroadcaster.cs b/Hazel/Udp/UdpBroadcaster.cs
new file mode 100644 (file)
index 0000000..872e685
--- /dev/null
@@ -0,0 +1,60 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+
+namespace Hazel.Udp
+{
+    ///
+    public class UdpBroadcaster : IDisposable
+    {
+        ///
+        private Socket socket;
+
+        ///
+        private byte[] data;
+
+        ///
+        private EndPoint endpoint;
+
+        ///
+        public UdpBroadcaster(int port)
+        {
+            this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+            this.socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
+            this.endpoint = new IPEndPoint(IPAddress.Broadcast, port);
+        }
+
+        ///
+        public void SetData(string data)
+        {
+            int len = ASCIIEncoding.ASCII.GetByteCount(data);
+            this.data = new byte[len + 2];
+            this.data[0] = 4;
+            this.data[1] = 2;
+
+            ASCIIEncoding.ASCII.GetBytes(data, 0, data.Length, this.data, 2);
+        }
+
+        ///
+        public void Broadcast()
+        {
+            if (this.data == null)
+            {
+                return;
+            }
+
+            this.socket.BeginSendTo(data, 0, data.Length, SocketFlags.None, this.endpoint, (evt) => this.socket.EndSendTo(evt), null);
+        }
+
+        ///
+        public void Dispose()
+        {
+            if (this.socket != null)
+            {
+                this.socket.Close();
+                this.socket = null;
+            }
+        }
+    }
+}
\ No newline at end of file