using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace Crestron.SimplSharp.CrestronSockets
{
/// Mock UDPServer class for UDP communication
public class UDPServer : IDisposable
{
private UdpClient? _udpClient;
private bool _listening;
private readonly object _lockObject = new object();
private CancellationTokenSource? _cancellationTokenSource;
/// Event fired when data is received
public event UDPServerReceiveDataEventHandler? ReceivedData;
/// Gets the server state
public SocketServerState State { get; private set; } = SocketServerState.SERVER_NOT_LISTENING;
/// Gets the server status (alias for State)
public SocketServerState ServerStatus => State;
/// Gets the client status as SocketStatus
public SocketStatus ClientStatus => State == SocketServerState.SERVER_LISTENING ? SocketStatus.SOCKET_STATUS_CONNECTED : SocketStatus.SOCKET_STATUS_NOT_CONNECTED;
/// Gets or sets the port number
public int PortNumber { get; set; }
/// Gets the buffer size
public int BufferSize { get; private set; }
/// Gets the IP address of the last message received from
public string IPAddressLastMessageReceivedFrom { get; private set; } = string.Empty;
/// Gets the IP port of the last message received from
public int IPPortLastMessageReceivedFrom { get; private set; }
/// Gets the incoming data buffer
public byte[] IncomingDataBuffer { get; private set; } = new byte[0];
/// Initializes a new instance of UDPServer
public UDPServer()
{
PortNumber = 0;
BufferSize = 1024;
}
/// Initializes a new instance of UDPServer
/// IP address to bind to
/// Port number to listen on
/// Buffer size for data reception
/// Ethernet adapter to bind to
public UDPServer(string ipAddress, int portNumber, int bufferSize, EthernetAdapterType ethernetAdapterToBindTo)
{
PortNumber = portNumber;
BufferSize = bufferSize;
}
/// Initializes a new instance of UDPServer
/// Port number to listen on
/// Buffer size for data reception
public UDPServer(int portNumber, int bufferSize)
{
PortNumber = portNumber;
BufferSize = bufferSize;
}
/// Starts listening for UDP packets
/// SocketErrorCodes indicating success or failure
public SocketErrorCodes EnableUDPServer()
{
if (_listening)
return SocketErrorCodes.SOCKET_OPERATION_PENDING;
try
{
_udpClient = new UdpClient(PortNumber);
_listening = true;
State = SocketServerState.SERVER_LISTENING;
_cancellationTokenSource = new CancellationTokenSource();
_ = Task.Run(() => ReceiveDataAsync(_cancellationTokenSource.Token));
return SocketErrorCodes.SOCKET_OK;
}
catch (Exception)
{
State = SocketServerState.SERVER_NOT_LISTENING;
return SocketErrorCodes.SOCKET_CONNECTION_FAILED;
}
}
/// Starts listening for UDP packets on specified hostname and port
/// Hostname to bind to
/// Port number to listen on
/// SocketErrorCodes indicating success or failure
public SocketErrorCodes EnableUDPServer(string hostname, int port)
{
PortNumber = port;
return EnableUDPServer();
}
/// Stops listening for UDP packets
/// SocketErrorCodes indicating success or failure
public SocketErrorCodes DisableUDPServer()
{
if (!_listening)
return SocketErrorCodes.SOCKET_NOT_CONNECTED;
try
{
_listening = false;
_cancellationTokenSource?.Cancel();
_udpClient?.Close();
State = SocketServerState.SERVER_NOT_LISTENING;
return SocketErrorCodes.SOCKET_OK;
}
catch (Exception)
{
return SocketErrorCodes.SOCKET_CONNECTION_FAILED;
}
}
/// Sends data to a specific endpoint
/// Data to send
/// Length of data
/// Target IP address
/// Target port number
/// SocketErrorCodes indicating success or failure
public SocketErrorCodes SendData(byte[] data, int dataLength, string ipAddress, int portNumber)
{
if (!_listening || _udpClient == null)
return SocketErrorCodes.SOCKET_NOT_CONNECTED;
try
{
var endpoint = new IPEndPoint(IPAddress.Parse(ipAddress), portNumber);
_udpClient.Send(data, dataLength, endpoint);
return SocketErrorCodes.SOCKET_OK;
}
catch (Exception)
{
return SocketErrorCodes.SOCKET_CONNECTION_FAILED;
}
}
/// Sends data to the last received endpoint
/// Data to send
/// Length of data
/// SocketErrorCodes indicating success or failure
public SocketErrorCodes SendData(byte[] data, int dataLength)
{
return SendData(data, dataLength, IPAddressLastMessageReceivedFrom, IPPortLastMessageReceivedFrom);
}
/// Receives data asynchronously
/// Callback to invoke when data is received
/// SocketErrorCodes indicating success or failure
public SocketErrorCodes ReceiveDataAsync(UDPServerReceiveDataEventHandler callback)
{
ReceivedData += callback;
return SocketErrorCodes.SOCKET_OK;
}
/// Receives data asynchronously with simple callback
/// Simple callback to invoke when data is received
/// SocketErrorCodes indicating success or failure
public SocketErrorCodes ReceiveDataAsync(UDPServerReceiveDataSimpleEventHandler callback)
{
// Convert simple callback to full event handler and subscribe
ReceivedData += (server, args) => callback(server, args.DataLength);
return SocketErrorCodes.SOCKET_OK;
}
/// Sends data to a specific endpoint
/// Data to send
/// Length of data
/// Target endpoint
/// SocketErrorCodes indicating success or failure
public SocketErrorCodes SendData(byte[] data, int dataLength, IPEndPoint endpoint)
{
if (!_listening || _udpClient == null)
return SocketErrorCodes.SOCKET_NOT_CONNECTED;
try
{
_udpClient.Send(data, dataLength, endpoint);
return SocketErrorCodes.SOCKET_OK;
}
catch (Exception)
{
return SocketErrorCodes.SOCKET_CONNECTION_FAILED;
}
}
private async Task ReceiveDataAsync(CancellationToken cancellationToken)
{
while (_listening && _udpClient != null && !cancellationToken.IsCancellationRequested)
{
try
{
var result = await _udpClient.ReceiveAsync();
var args = new UDPServerReceiveDataEventArgs(
result.Buffer,
result.Buffer.Length,
result.RemoteEndPoint.Address.ToString(),
result.RemoteEndPoint.Port);
ReceivedData?.Invoke(this, args);
}
catch (ObjectDisposedException)
{
// UDP client was disposed
break;
}
catch (Exception)
{
// Handle other exceptions
continue;
}
}
}
/// Disposes the UDPServer
public void Dispose()
{
DisableUDPServer();
_cancellationTokenSource?.Dispose();
_udpClient?.Dispose();
}
}
// Event handler delegates for UDP
public delegate void UDPServerReceiveDataEventHandler(UDPServer server, UDPServerReceiveDataEventArgs args);
public delegate void UDPServerReceiveDataSimpleEventHandler(UDPServer server, int numBytes);
// Event argument classes for UDP
public class UDPServerReceiveDataEventArgs : EventArgs
{
/// Gets the received data
public byte[] Data { get; }
/// Gets the length of received data
public int DataLength { get; }
/// Gets the sender's IP address
public string IPAddress { get; }
/// Gets the sender's port number
public int Port { get; }
/// Initializes a new instance of UDPServerReceiveDataEventArgs
/// Received data
/// Length of received data
/// Sender's IP address
/// Sender's port number
public UDPServerReceiveDataEventArgs(byte[] data, int dataLength, string ipAddress, int port)
{
Data = data;
DataLength = dataLength;
IPAddress = ipAddress;
Port = port;
}
}
}