// Copyright (c) 2010, Peter Smith
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this list
// of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above copyright notice, this
// list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// Neither the name of the Author nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
namespace SocketCommunications
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class BroadCastReceive : IDisposable
{
#region Fields
/// <summary>
/// Queue used to hold the PDU packets received from the socket
/// </summary>
public Queue<byte[]> pduQueue = new Queue<byte[]>();
const int defaultPortNumber = 9737;
private static IPAddress address;
private static Socket socket;
private bool closing = false;
private int MTU = 1500;
private int receivePort;
private object socketLock;
private bool socketMethodEnded = false;
private Thread udpListen;
#endregion Fields
#region Constructors
/// <summary>
/// BroadCast constructor.
/// </summary>
public BroadCastReceive(string ipAddress, int portReceiveNumber)
{
address = IPAddress.Parse(ipAddress);
this.ReceivePort = portReceiveNumber;
socketLock = new object();
if (StartBroadCastReceive(address))
{
udpListen = new Thread(ReceiveBroadcastMessages);
udpListen.Name = "BroadCast Reveive Thread";
udpListen.Start();
}
}
#endregion Constructors
#region Properties
public int ReceivePort
{
get
{
return receivePort;
}
set
{
if (value >= 0 || value < 65336)
receivePort = value;
else
receivePort = defaultPortNumber;
}
}
#endregion Properties
#region Methods
/// <summary>
/// Dispose
/// </summary>
public void Dispose()
{
CloseSocket();
}
void IDisposable.Dispose()
{
Dispose();
}
/// <summary>
/// Reconnects
/// </summary>
public void Reconnect(IPAddress ipAddress)
{
udpListen.Abort();
// CloseSocket();
if (StartBroadCastReceive(ipAddress))
{
udpListen = new Thread(ReceiveBroadcastMessages);
udpListen.Start();
}
}
/// <summary>
/// Shut down the socket
/// </summary>
public void ShutDownSocket()
{
Disconnect();
}
private void CloseSocket()
{
if (socket != null)
{
if (socket.Connected == true)
socket.Disconnect(true);
socket.Shutdown(SocketShutdown.Both);
socket.Close();
socket = null;
}
}
/// <summary>
/// Disconnects socket and end thread
/// </summary>
private void Disconnect()
{
closing = true;
pduQueue.Clear();
CloseSocket();
if (udpListen != null && udpListen.IsAlive == true)
udpListen.Abort();
}
private void ReceiveBroadcastMessages()
{
byte[] bytes;
EndPoint remoteEP = (EndPoint)new IPEndPoint(IPAddress.Any, 0);
try
{
do
{
//lock (socketLock)
//{
bytes = new Byte[MTU];
socket.ReceiveFrom(bytes, ref remoteEP);
if (bytes != null)
{
pduQueue.Enqueue(bytes);
}
Thread.Sleep(1);
}
while (!closing);
}
catch (SocketException e)
{
if (closing == false)
{
Trace.WriteLine("Exception [SocketException] caught ReceiveBroadcastMessages :[" + Environment.NewLine + e.Message + "]");
throw;
}
}
catch (ThreadAbortException)
{
//is always thrown when a thread is aborted
CloseSocket();
}
//catch (ThreadInterruptedException) //Not in compact framework
//{
// CloseSocket();
//}
catch (Exception e)
{
Trace.WriteLine("Exception [" + e.GetType().ToString() + "] caught ReceiveBroadcastMessages:[" + Environment.NewLine + e.Message + "]");
CloseSocket();
throw;
}
finally
{
socketMethodEnded = true;
}
}
private bool StartBroadCastReceive(IPAddress ipAddress)
{
try
{
lock (socketLock)
{
EndPoint localEP = (EndPoint)new IPEndPoint(IPAddress.Any, this.ReceivePort); //Listen to all interfaces
socket = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram,
ProtocolType.Udp);
socket.EnableBroadcast = true;
//Removed to make cross platform building easier
//Does not appear that linux supports multiple applications using the same port for listening
//#if (!MONO)
// socket.ExclusiveAddressUse = false;
//#endif
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
socket.Bind(localEP);
}
return true;
}
catch (Exception e)
{
Trace.WriteLine("Exception [" + e.GetType().ToString() + "] caught Start BroadCastReceive");
return false;
}
}
#endregion Methods
}
}