using System; using Sys = System; using System.Collections.Generic; namespace Cosmos.System.Network { /// /// UdpClient class. Used to manage the UDP connection to a client. /// public class UdpClient { // TODO: Once we support more than just IPv4, we really need to base all the IPv4 classes on abstract classes // that represent the required functionality, then we can generalize the stack to be independent from IPv4 or IPv6 /// /// Datagram class. /// internal class DataGram { /// /// Data array. /// internal byte[] data; /// /// Source end point. /// internal IPv4.EndPoint source; /// /// Create new inctanse of the class. /// /// Data array. /// Source end point. internal DataGram(byte[] data, IPv4.EndPoint src) { this.data = data; this.source = src; } } /// /// Clients dictionary. /// private static TempDictionary clients; /// /// Local port. /// protected Int32 localPort; /// /// Destination address. /// protected IPv4.Address destination; /// /// Destination port. /// protected Int32 destinationPort; /// /// RX buffer queue. /// private Queue rxBuffer; /// /// Assign clients dictionary. /// /// Thrown on fatal error (contact support). static UdpClient() { clients = new TempDictionary(); } /// /// Get client. /// /// Destination port. /// UdpClient internal static UdpClient Client(ushort destPort) { if (clients.ContainsKey((UInt32)destPort) == true) { return clients[(UInt32)destPort]; } return null; } /// /// Create new inctanse of the class. /// /// Thrown on fatal error (contact support). /// Thrown if UdpClient with localPort 0 exists. public UdpClient() :this(0) { } /// /// Create new inctanse of the class. /// /// Local port. /// Thrown on fatal error (contact support). /// Thrown if localPort already exists. public UdpClient(Int32 localPort) { this.rxBuffer = new Queue(8); this.localPort = localPort; if (localPort > 0) { UdpClient.clients.Add((UInt32)localPort, this); } } /// /// Create new inctanse of the class. /// /// Destination address. /// Destination port. /// Thrown on fatal error (contact support). /// Thrown if UdpClient with localPort 0 exists. public UdpClient(IPv4.Address dest, Int32 destPort) : this(0) { this.destination = dest; this.destinationPort = destPort; } /// /// Connect to client. /// /// Destination address. /// Destination port. public void Connect(IPv4.Address dest, Int32 destPort) { this.destination = dest; this.destinationPort = destPort; } /// /// Send data to client. /// /// Data array to send. /// Thrown if destination is null or destinationPort is 0. /// Thrown on fatal error (contact support). /// Thrown if data array length is greater than Int32.MaxValue. /// Thrown on IO error. public void Send(byte[] data) { if ((this.destination == null) || (this.destinationPort == 0)) { throw new Exception("Must establish a default remote host by calling Connect() before using this Send() overload"); } Send(data, this.destination, this.destinationPort); } /// /// Send data. /// /// Data array. /// Destination address. /// Destination port. /// Thrown on fatal error (contact support). /// Thrown if data array length is greater than Int32.MaxValue. /// Thrown on IO error. public void Send(byte[] data, IPv4.Address dest, Int32 destPort) { IPv4.Address source = IPv4.Config.FindNetwork(dest); IPv4.UDPPacket packet = new IPv4.UDPPacket(source, dest, (UInt16)this.localPort, (UInt16)destPort, data); Sys.Console.WriteLine("Sending " + packet.ToString()); IPv4.OutgoingBuffer.AddPacket(packet); } /// /// Close connection. /// /// Thrown on fatal error (contact support). public void Close() { if (UdpClient.clients.ContainsKey((UInt32)this.localPort) == true) { UdpClient.clients.Remove((UInt32)this.localPort); } } /// /// Receive data from end point. /// /// Source end point. /// byte array value. /// Thrown on fatal error (contact support). public byte[] Receive(ref IPv4.EndPoint source) { if (this.rxBuffer.Count < 1) { return null; } DataGram packet = rxBuffer.Dequeue(); source.address = packet.source.address; source.port = packet.source.port; return packet.data; } /// /// Receive data from packet. /// /// Packet to receive. /// Thrown on fatal error (contact support). /// Thrown on IO error. internal void receiveData(IPv4.UDPPacket packet) { byte[] data = packet.UDP_Data; IPv4.EndPoint source = new IPv4.EndPoint(packet.SourceIP, packet.SourcePort); Sys.Console.WriteLine("Received " + data.Length + " bytes data from " + source.ToString()); this.rxBuffer.Enqueue(new DataGram(data, source)); } } }