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; } } }