diff --git a/Build/VMWare/Workstation/Cosmos.vmx b/Build/VMWare/Workstation/Cosmos.vmx index 7a71985182..da62d2a6ce 100644 --- a/Build/VMWare/Workstation/Cosmos.vmx +++ b/Build/VMWare/Workstation/Cosmos.vmx @@ -51,8 +51,11 @@ serial0.pipe.endPoint = "client" serial0.tryNoRxLoss = "TRUE" sound.present = "TRUE" ethernet0.present = "TRUE" -ethernet0.wakeOnPcktRcv = "FALSE" +ethernet0.connectionType = "nat" ethernet0.addressType = "generated" +ethernet0.generatedAddress = "00:0c:29:0c:c9:44" +ethernet0.generatedAddressOffset = "0" +ethernet0.pciSlotNumber = "34" usb.present = "TRUE" usb.generic.allowHID = "TRUE" ehci.present = "TRUE" diff --git a/Docs/articles/Kernel/VFS.md b/Docs/articles/Kernel/VFS.md index b0103a7684..8b5e41b6bf 100644 --- a/Docs/articles/Kernel/VFS.md +++ b/Docs/articles/Kernel/VFS.md @@ -45,7 +45,7 @@ Console.WriteLine("Available Free Space: " + available_space); You have probably noticed the "0:\" argument passed to this function, this is the id of the drive that we want to get available free space of. Cosmos using DOS drive naming system and this is why we use "0". -**Attention**: Typing "0:/" instead of "0:\" might lead to errors, you've been warned. +**Attention**: Typing "0:/" instead of "0:\\" might lead to errors, you've been warned. ## Get file system type diff --git a/Tests/Cosmos.TestRunner.Core/Engine.Run.cs b/Tests/Cosmos.TestRunner.Core/Engine.Run.cs index 0a1f133ce8..42955d92f5 100644 --- a/Tests/Cosmos.TestRunner.Core/Engine.Run.cs +++ b/Tests/Cosmos.TestRunner.Core/Engine.Run.cs @@ -1,6 +1,10 @@ using System; using System.Collections.Generic; using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; namespace Cosmos.TestRunner.Core { @@ -49,22 +53,34 @@ private bool ExecuteKernel( RunTask("MakeISO", () => MakeIso(xObjectFile, xIsoFile)); - switch (configuration.RunTarget) + Console.WriteLine("assemblyFileName=" + assemblyFileName); + + if (assemblyFileName.EndsWith("NetworkTest.dll")) + { + var serverThread = new Thread(StartTcpServer); + serverThread.Start(); + + RunTask("RunISO", () => RunIsoInVMware(xIsoFile, xHarddiskPath)); + } + else { - case RunTargetEnum.Bochs: - RunTask("RunISO", () => RunIsoInBochs(xIsoFile, xHarddiskPath, workingDirectory)); - break; - case RunTargetEnum.Qemu: - RunTask("RunISO", () => RunIsoInQemu(xIsoFile, xHarddiskPath, workingDirectory)); - break; - case RunTargetEnum.VMware: - RunTask("RunISO", () => RunIsoInVMware(xIsoFile, xHarddiskPath)); - break; - case RunTargetEnum.HyperV: - RunTask("RunISO", () => RunIsoInHyperV(xIsoFile, xHarddiskPath)); - break; - default: - throw new ArgumentOutOfRangeException("RunTarget " + configuration.RunTarget + " not implemented!"); + switch (configuration.RunTarget) + { + case RunTargetEnum.Bochs: + RunTask("RunISO", () => RunIsoInBochs(xIsoFile, xHarddiskPath, workingDirectory)); + break; + case RunTargetEnum.Qemu: + RunTask("RunISO", () => RunIsoInQemu(xIsoFile, xHarddiskPath, workingDirectory)); + break; + case RunTargetEnum.VMware: + RunTask("RunISO", () => RunIsoInVMware(xIsoFile, xHarddiskPath)); + break; + case RunTargetEnum.HyperV: + RunTask("RunISO", () => RunIsoInHyperV(xIsoFile, xHarddiskPath)); + break; + default: + throw new ArgumentOutOfRangeException("RunTarget " + configuration.RunTarget + " not implemented!"); + } } OutputHandler.ExecuteKernelEnd(assemblyFileName); @@ -94,5 +110,102 @@ private void RunTask(string aTaskName, Action aAction) OutputHandler.TaskEnd(aTaskName); } } + + private void StartTcpServer() + { + var listener = new TcpListener(IPAddress.Loopback, 12345); + listener.Start(); + + Console.WriteLine("TCP server started in a new thread, waiting connection from test kernel..."); + + IPEndPoint localEndPoint = listener.LocalEndpoint as IPEndPoint; + Console.WriteLine($"IP: {localEndPoint.Address}, Port: {localEndPoint.Port}"); + + var client = listener.AcceptTcpClient(); + var remoteEndPoint = client.Client.RemoteEndPoint as IPEndPoint; + var clientIPAddress = remoteEndPoint.Address; + Console.WriteLine("Test kernel connected! Beginning tests..."); + + IPAddress remoteIPAddress = null; + + using (NetworkStream stream = client.GetStream()) + { + // Test 1: Send simple message + string testMessage = "Hello from the testrunner!"; + byte[] messageBytes = Encoding.ASCII.GetBytes(testMessage); + stream.Write(messageBytes, 0, messageBytes.Length); + Console.WriteLine($"Sent: {testMessage}"); + + // Test 2: Receive a message from kernel + byte[] bufferIp = new byte[1024]; + int bytesIpRead = stream.Read(bufferIp, 0, bufferIp.Length); + string ip = Encoding.ASCII.GetString(bufferIp, 0, bytesIpRead); + remoteIPAddress = IPAddress.Parse(ip); + Console.WriteLine($"Received: {ip}"); + + // Test 2.2: Receive a message from kernel + byte[] buffer = new byte[1024]; + int bytesRead = stream.Read(buffer, 0, buffer.Length); + string receivedMessage = Encoding.ASCII.GetString(buffer, 0, bytesRead); + Console.WriteLine($"Received: {receivedMessage}"); + + // Test 3: Send back the received message, capitalized + string replyMessage = receivedMessage.ToUpper(); + byte[] replyBytes = Encoding.ASCII.GetBytes(replyMessage); + stream.Write(replyBytes, 0, replyBytes.Length); + Console.WriteLine($"Sent: {replyMessage}"); + + // Test 4: Receive a big packet from kernel to test TCP sequencing + byte[] buffer2 = new byte[6000]; + int totalBytesRead = 0; + + while (totalBytesRead < 6000) + { + totalBytesRead += stream.Read(buffer2, totalBytesRead, 6000 - totalBytesRead); + } + + // Test 5: Send back the received message + stream.Write(buffer2, 0, buffer2.Length); + Console.WriteLine($"Sent: {replyMessage}"); + } + + client.Close(); + listener.Stop(); + + ConnectToTcpServer(remoteIPAddress); + } + + private void ConnectToTcpServer(IPAddress ip) + { + var xClient = new TcpClient(); + + Console.WriteLine("Attempting to connect to the kernel..."); + + try + { + // Test 6: Test TCPListener implementation + xClient.Connect(ip, 4343); + Console.WriteLine("Connected to the kernel!"); + + using (NetworkStream stream = xClient.GetStream()) + { + byte[] buffer = new byte[1024]; + int bytesRead = stream.Read(buffer, 0, buffer.Length); + string receivedMessage = Encoding.ASCII.GetString(buffer, 0, bytesRead); + Console.WriteLine($"Received: {receivedMessage}"); + + string testMessage = "Hello from the testrunner again!"; + byte[] messageBytes = Encoding.ASCII.GetBytes(testMessage); + stream.Write(messageBytes, 0, messageBytes.Length); + Console.WriteLine($"Sent: {testMessage}"); + } + + xClient.Close(); + } + catch (SocketException ex) + { + Console.WriteLine($"Failed to connect to the kernel. Error: {ex.Message}"); + } + } } } diff --git a/Tests/Cosmos.TestRunner.Full/TestKernelSets.cs b/Tests/Cosmos.TestRunner.Full/TestKernelSets.cs index 1137fdc734..6e2f0e1c35 100644 --- a/Tests/Cosmos.TestRunner.Full/TestKernelSets.cs +++ b/Tests/Cosmos.TestRunner.Full/TestKernelSets.cs @@ -30,7 +30,9 @@ public static IEnumerable GetStableKernelTypes() //yield return typeof(KernelGen3.Boot); yield return typeof(GraphicTest.Kernel); - yield return typeof(NetworkTest.Kernel); + + // Disable network tests due to our self hosted CI/CD limitations (VPS currently doesn't support VMWare with its CPU) + //yield return typeof(NetworkTest.Kernel); yield return typeof(AudioTests.Kernel); // Please see the notes on the kernel itself before enabling it //yield return typeof(ConsoleTest.Kernel); diff --git a/Tests/Kernels/NetworkTest/Kernel.cs b/Tests/Kernels/NetworkTest/Kernel.cs index 1d1a5bfdfb..22bd4c8502 100644 --- a/Tests/Kernels/NetworkTest/Kernel.cs +++ b/Tests/Kernels/NetworkTest/Kernel.cs @@ -8,6 +8,7 @@ using Cosmos.System.Network.IPv4.UDP.DHCP; using Cosmos.System.Network.IPv4.UDP.DNS; using Cosmos.TestRunner; +using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; using System; using System.Collections.Generic; using System.Text; @@ -19,53 +20,56 @@ public class Kernel : Sys.Kernel { protected override void BeforeRun() { + Console.WriteLine("Cosmos booted successfully. Starting Tests"); } protected override void Run() { - /** - * Packet creation and parsing tests - **/ - - /** Ethernet Packet Parsing Test **/ - byte[] ethernetPacketData = new byte[] + try { + /** + * Packet creation and parsing tests + **/ + + /** Ethernet Packet Parsing Test **/ + byte[] ethernetPacketData = new byte[] + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0C, 0x29, 0xD5, 0xDB, 0x9D, 0x08, 0x00 - }; - EthernetPacket ethernetPacket = new EthernetPacket(ethernetPacketData); - Equals(ethernetPacketData, ethernetPacket.RawData); + }; + EthernetPacket ethernetPacket = new EthernetPacket(ethernetPacketData); + Assert.AreEqual(ethernetPacketData, ethernetPacket.RawData, "Ethernet packet data is good."); - /** IP Packet Parsing Test **/ - byte[] ipPacketData = new byte[] - { + /** IP Packet Parsing Test **/ + byte[] ipPacketData = new byte[] + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0C, 0x29, 0xD5, 0xDB, 0x9D, 0x08, 0x00, 0x45, 0x00, 0x01, 0x16, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x39, 0xD8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF - }; - IPPacket ipPacket = new IPPacket(ipPacketData); - Equals(ipPacketData, ipPacket.RawData); + }; + IPPacket ipPacket = new IPPacket(ipPacketData); + Assert.AreEqual(ipPacketData, ipPacket.RawData, "IP packet data is good."); - /** UDP Packet Parsing Test **/ - byte[] udpPacketData = new byte[] - { + /** UDP Packet Parsing Test **/ + byte[] udpPacketData = new byte[] + { 0x98, 0xFA, 0x9B, 0xD4, 0xEB, 0x29, 0xD8, 0xCE, 0x3A, 0x89, 0x3E, 0xD9, 0x08, 0x00, 0x45, 0x00, 0x00, 0x22, 0x0C, 0x74, 0x40, 0x00, 0x40, 0x11, 0xAA, 0xBE, 0xC0, 0xA8, 0x01, 0x02, 0xC0, 0xA8, 0x01, 0x46, 0x10, 0x92, 0x10, 0x92, 0x00, 0x0E, 0x37, 0x22, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x21 - }; - UDPPacket udpPacket = new UDPPacket(udpPacketData); - Equals(udpPacketData, udpPacket.RawData); + }; + UDPPacket udpPacket = new UDPPacket(udpPacketData); + Assert.AreEqual(udpPacketData, udpPacket.RawData, "UDP packet data is good."); - /** DNS Packet Parsing Test **/ - byte[] dnsPacketData = new byte[] - { + /** DNS Packet Parsing Test **/ + byte[] dnsPacketData = new byte[] + { 0xB8, 0xD9, 0x4D, 0xC1, 0xA5, 0xFC, 0x98, 0xFA, 0x9B, 0xD4, 0xEB, 0x29, 0x08, 0x00, 0x45, 0x00, 0x00, 0x38, 0xC3, 0x1C, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0xC0, 0xA8, 0x01, 0x46, 0xC0, 0xA8, 0x01, 0xFE, 0xF0, 0x66, 0x00, 0x35, 0x00, 0x24, 0x84, 0xCA, 0xD6, 0x80, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x67, 0x69, 0x74, 0x74, 0x65, 0x72, 0x03, 0x63, 0x6F, 0x6D, 0x00, 0x00, 0x01, 0x00, 0x01 - }; - DNSPacket dnsPacket = new DNSPacket(dnsPacketData); - Equals(dnsPacketData, dnsPacket.RawData); + }; + DNSPacket dnsPacket = new DNSPacket(dnsPacketData); + Assert.AreEqual(dnsPacketData, dnsPacket.RawData, "DNS packet data is good."); - /** DHCP Packet Parsing Test **/ - byte[] dhcpPacketData = new byte[] - { + /** DHCP Packet Parsing Test **/ + byte[] dhcpPacketData = new byte[] + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xB8, 0xD9, 0x4D, 0xC1, 0xA5, 0xFC, 0x08, 0x00, 0x45, 0xC0, 0x01, 0x59, 0x46, 0x3F, 0x00, 0x00, 0x40, 0x11, 0x6F, 0xEF, 0xC0, 0xA8, 0x01, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x43, 0x00, 0x44, 0x01, 0x45, 0xD3, 0xC8, 0x02, 0x01, 0x06, 0x00, 0x84, 0xA9, 0x5A, 0x66, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8, 0x01, 0x47, 0xC0, 0xA8, 0x01, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x34, 0xE1, 0x2D, 0xA3, 0x06, @@ -81,56 +85,148 @@ protected override void Run() 0x00, 0xA8, 0xC0, 0x3B, 0x04, 0x00, 0x01, 0x27, 0x50, 0x1C, 0x04, 0xC0, 0xA8, 0x01, 0xFF, 0x51, 0x12, 0x03, 0xFF, 0xFF, 0x44, 0x45, 0x53, 0x4B, 0x54, 0x4F, 0x50, 0x2D, 0x49, 0x51, 0x48, 0x4A, 0x33, 0x31, 0x43, 0x06, 0x04, 0xC0, 0xA8, 0x01, 0xFE, 0x0F, 0x03, 0x6C, 0x61, 0x6E, 0x03, 0x04, 0xC0, 0xA8, 0x01, 0xFE, 0x01, 0x04, 0xFF, 0xFF, 0xFF, 0x00, 0xFF - }; - DHCPPacket dhcpPacket = new DHCPPacket(dhcpPacketData); - Equals(dhcpPacketData, dhcpPacket.RawData); + }; + DHCPPacket dhcpPacket = new DHCPPacket(dhcpPacketData); + Assert.AreEqual(dhcpPacketData, dhcpPacket.RawData, "DHCP packet data is good."); - /** TCP Packet Parsing Test **/ - byte[] tcpPacketData = new byte[] - { + /** TCP Packet Parsing Test **/ + byte[] tcpPacketData = new byte[] + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x00, 0x45, 0x00, 0x00, 0x3C, 0x64, 0x92, 0x40, 0x00, 0x40, 0x06, 0x51, 0xA2, 0xC0, 0xA8, 0x01, 0xD3, 0xC0, 0xA8, 0x01, 0x64, 0xA8, 0xAB, 0x10, 0x92, 0x67, 0x7C, 0xCE, 0x18, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x02, 0x72, 0x10, 0x5F, 0xF0, 0x00, 0x00, 0x02, 0x04, 0x05, 0xB4, 0x04, 0x02, 0x08, 0x0A, 0x58, 0x1A, 0xAA, 0x8A, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07 - }; - TCPPacket tcpPacket = new TCPPacket(tcpPacketData); - Equals(tcpPacket.SourcePort, 43179); - Equals(tcpPacket.DestinationPort, 4242); - Equals(tcpPacket.SequenceNumber, 0x677CCE18); - Equals(tcpPacket.AckNumber, 0); - Equals(tcpPacket.TCPFlags, Flags.SYN); - Equals(tcpPacket.WindowSize, 29200); - Equals(tcpPacket.Checksum, 0x5FF0); - Equals(tcpPacket.UrgentPointer, 0); - - /** ARP Packet Parsing Test **/ - byte[] arpPacketData = new byte[] - { + }; + TCPPacket tcpPacket = new TCPPacket(tcpPacketData); + Assert.AreEqual(tcpPacket.SourcePort, 43179, "TCP source port parsing OK."); + Assert.AreEqual(tcpPacket.DestinationPort, 4242, "TCP destination port parsing OK."); + Assert.AreEqual(tcpPacket.SequenceNumber, 0x677CCE18, "TCP sequence number parsing OK."); + Assert.AreEqual(tcpPacket.AckNumber, 0, "TCP ACK number parsing OK."); + Assert.AreEqual(tcpPacket.TCPFlags, (int)Flags.SYN, "TCP flag parsing OK."); + Assert.AreEqual(tcpPacket.WindowSize, 29200, "TCP window size parsing OK."); + Assert.AreEqual(tcpPacket.Checksum, 0x5FF0, "TCP checksum parsing OK."); + Assert.AreEqual(tcpPacket.UrgentPointer, 0, "TCP urgent pointer parsing OK."); + + /** ARP Packet Parsing Test **/ + byte[] arpPacketData = new byte[] + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xB8, 0xD9, 0x4D, 0xC1, 0xA5, 0xFC, 0x08, 0x06, 0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xB8, 0xD9, 0x4D, 0xC1, 0xA5, 0xFC, 0xC0, 0xA8, 0x01, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA8, 0x01, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - ARPPacket arpPacket = new ARPPacket(arpPacketData); - Equals(arpPacketData, arpPacket.RawData); + }; + ARPPacket arpPacket = new ARPPacket(arpPacketData); + Assert.AreEqual(arpPacketData, arpPacket.RawData, "ARP packet data is good."); + + /** + * Clients tests + **/ + TestDhcpConnection(); + TestTcpConnection(); + TestDnsConnection(); + TestIcmpConnection(); + + TestController.Completed(); + } + catch (Exception e) + { + mDebugger.Send("Exception occurred: " + e.Message); + mDebugger.Send(e.Message); + TestController.Failed(); + } + } + + private void TestDhcpConnection() + { + Global.debugger.Send("Creating DHCP client..."); + + using (var xClient = new DHCPClient()) + { + xClient.SendDiscoverPacket(); + + var ip = NetworkConfiguration.CurrentAddress.ToString(); + Global.debugger.Send("IP: " + ip); + + Assert.IsTrue(ip != null, "Received IP is valid."); + Assert.IsFalse(NetworkConfiguration.CurrentAddress.Equals(Address.Zero), "Received IP is not ZERO, DHCP works"); + } + } + + private void TestTcpConnection() + { + Global.debugger.Send("Creating TCP client..."); + + using (var xClient = new TcpClient()) + { + Assert.IsTrue(xClient.IsClosed(), "TCP connexion created."); + + xClient.Connect(new Address(127, 0, 0, 1), 12345); + Assert.IsTrue(xClient.IsConnected(), "TCP connexion established."); + + var endpoint = new EndPoint(Address.Zero, 0); + var data = xClient.Receive(ref endpoint); + Assert.AreEqual(Encoding.ASCII.GetString(data), "Hello from the testrunner!", "TCP receive works"); + + xClient.Send(Encoding.ASCII.GetBytes(NetworkConfiguration.CurrentAddress.ToString())); + + xClient.Send(Encoding.ASCII.GetBytes("cosmos is the best operating system uwu")); + var data2 = xClient.Receive(ref endpoint); + Assert.AreEqual(Encoding.ASCII.GetString(data2), "COSMOS IS THE BEST OPERATING SYSTEM UWU", "TCP send works"); + + string baseMessage = "This is a long TCP message for sequencing test..."; + string paddedMessage = baseMessage.PadRight(6000, '.'); + xClient.Send(Encoding.ASCII.GetBytes(paddedMessage)); - TestController.Completed(); + var data3 = xClient.Receive(ref endpoint); + Assert.AreEqual(data3.Length, 6000, "TCP paquet sequencing works."); + } - /** - * Clients tests - **/ - var dhcpCLient = new DHCPClient(); - dhcpCLient.Close(); + Global.debugger.Send("Creating TCP server..."); + + using (var xServer = new TcpListener(4343)) + { + xServer.Start(); + Assert.IsTrue(xServer.IsListening(), "TCP server is listening."); + + var client = xServer.AcceptTcpClient(); //blocking + Assert.IsTrue(xServer.IsConnected(), "Received new client! TCP connexion established."); + } + } + + private void TestDnsConnection() + { + Global.debugger.Send("Creating DNS client..."); + + using (var xClient = new DnsClient()) + { + xClient.Connect(new Address(1, 1, 1, 1)); //Cloudflare DNS + + xClient.SendAsk("github.com"); + + /** Receive DNS Response **/ + Address destination = xClient.Receive(); //can set a timeout value + + var ip = destination.ToString(); + Assert.IsTrue(ip != null, "Received IP is valid."); + Assert.IsFalse(NetworkConfiguration.CurrentAddress.Equals(Address.Zero), "Received IP is not ZERO, DNS works"); + + Global.debugger.Send("IP: " + ip); + } + } + + private void TestIcmpConnection() + { + Global.debugger.Send("Creating ICMP client..."); + + using (var xClient = new ICMPClient()) + { + xClient.Connect(new Address(127, 0, 0, 1)); //Cloudflare DNS - var dnsClient = new DnsClient(); - dnsClient.Close(); + xClient.SendEcho(); - var udpClient = new UdpClient(); - udpClient.Close(); - - var tcpClient = new TcpClient(4242); - tcpClient.Close(); + var endpoint = new EndPoint(Address.Zero, 0); + int time = xClient.Receive(ref endpoint); - var icmpClient = new ICMPClient(); - icmpClient.Close(); + Assert.IsFalse(time == -1, "ICMP echo works"); + } } } } diff --git a/source/Cosmos.HAL2/Network/NetworkInit.cs b/source/Cosmos.HAL2/Network/NetworkInit.cs index 5fad2b9dbc..51f2d4e82a 100644 --- a/source/Cosmos.HAL2/Network/NetworkInit.cs +++ b/source/Cosmos.HAL2/Network/NetworkInit.cs @@ -23,7 +23,6 @@ public static void Init() if (device.VendorID == (ushort)VendorID.AMD && device.DeviceID == (ushort)DeviceID.PCNETII) { - Console.WriteLine("NIC IRQ: " + device.InterruptLine); var AMDPCNetIIDevice = new AMDPCNetII(device); @@ -42,10 +41,14 @@ public static void Init() if (device.VendorID == 0x10EC && device.DeviceID == 0x8139) { + Console.WriteLine("NIC IRQ: " + device.InterruptLine); + var RTL8139Device = new RTL8139(device); RTL8139Device.NameID = "eth" + NetworkDeviceID; + Console.WriteLine("Registered at " + RTL8139Device.NameID + " (" + RTL8139Device.MACAddress.ToString() + ")"); + RTL8139Device.Enable(); NetworkDeviceID++; @@ -153,10 +156,14 @@ public static void Init() device.DeviceID == (ushort)E1000DeviceID.IntelI219LM_2 ) { + Console.WriteLine("NIC IRQ: " + device.InterruptLine); + var E1000Device = new E1000(device); E1000Device.NameID = ("eth" + NetworkDeviceID); + Console.WriteLine("Registered at " + E1000Device.NameID + " (" + E1000Device.MACAddress.ToString() + ")"); + E1000Device.Enable(); NetworkDeviceID++; diff --git a/source/Cosmos.System2/Network/IPv4/TCP/TCPClient.cs b/source/Cosmos.System2/Network/IPv4/TCP/TCPClient.cs index af2dacd3f0..87a990b9c8 100644 --- a/source/Cosmos.System2/Network/IPv4/TCP/TCPClient.cs +++ b/source/Cosmos.System2/Network/IPv4/TCP/TCPClient.cs @@ -15,6 +15,15 @@ public class TcpClient : IDisposable /// public Tcp StateMachine; + /// + /// Initializes a new instance of the class. + /// + /// Thrown on fatal error. + /// Thrown if TcpClient with localPort 0 exists. + public TcpClient() : this(Tcp.GetDynamicPort()) + { + } + /// /// Initializes a new instance of the class. /// @@ -32,7 +41,7 @@ internal TcpClient(Tcp stateMachine) /// The local port. /// Thrown on fatal error. /// Thrown if localPort already exists. - public TcpClient(int localPort) + internal TcpClient(int localPort) { StateMachine = new((ushort)localPort, 0, Address.Zero, Address.Zero); StateMachine.RxBuffer = new Queue(8); @@ -47,7 +56,7 @@ public TcpClient(int localPort) /// Thrown on fatal error. /// Thrown if TcpClient with localPort 0 exists. public TcpClient(Address dest, int destPort) - : this(0) + : this(Tcp.GetDynamicPort()) { StateMachine.RemoteEndPoint.Address = dest; StateMachine.RemoteEndPoint.Port = (ushort)destPort; @@ -236,6 +245,14 @@ public bool IsConnected() return StateMachine.Status == Status.ESTABLISHED; } + /// + /// Returns a value whether the TCP client is closed + /// + public bool IsClosed() + { + return StateMachine.Status == Status.CLOSED; + } + public void Dispose() { Close(); diff --git a/source/Cosmos.System2/Network/IPv4/TCP/TCPPacket.cs b/source/Cosmos.System2/Network/IPv4/TCP/TCPPacket.cs index c9df3b1238..dc91c98932 100644 --- a/source/Cosmos.System2/Network/IPv4/TCP/TCPPacket.cs +++ b/source/Cosmos.System2/Network/IPv4/TCP/TCPPacket.cs @@ -469,7 +469,9 @@ public string getFlags() /// string value. public override string ToString() { - return $"TCP Packet {SourceIP}:{SourcePort} -> {DestinationIP}:{DestinationPort} (flags={getFlags()}, seq={SequenceNumber}, ack={AckNumber})"; + return "TCP Packet " + SourceIP + ":" + SourcePort + + " -> " + DestinationIP + ":" + DestinationPort + " (flags=" + getFlags() + + ", seq=" + SequenceNumber + ", ack=" + AckNumber + ")"; } } } diff --git a/source/Cosmos.System2/Network/IPv4/TCP/Tcp.cs b/source/Cosmos.System2/Network/IPv4/TCP/Tcp.cs index c9abeda834..2506c53f9f 100644 --- a/source/Cosmos.System2/Network/IPv4/TCP/Tcp.cs +++ b/source/Cosmos.System2/Network/IPv4/TCP/Tcp.cs @@ -189,7 +189,7 @@ public static ushort GetDynamicPort(int tries = 10) /// /// String / enum correspondance (used for debugging) /// - internal static string[] Table; + internal static readonly string[] Table; static Tcp() { @@ -314,7 +314,7 @@ public Tcp(ushort localPort, ushort remotePort, Address localIp, Address remoteI /// Thrown on IO error. internal void ReceiveData(TCPPacket packet) { - NetworkStack.Debugger.Send("[" + Table[(int)Status] + "] " + packet.ToString()); + Cosmos.HAL.Global.debugger.Send("[" + Table[(int)Status] + "] " + packet.ToString()); /*if (Status == Status.CLOSED) { diff --git a/source/Cosmos.System2/Network/IPv4/TCP/TcpListener.cs b/source/Cosmos.System2/Network/IPv4/TCP/TcpListener.cs index dc483ac267..30e8d831ff 100644 --- a/source/Cosmos.System2/Network/IPv4/TCP/TcpListener.cs +++ b/source/Cosmos.System2/Network/IPv4/TCP/TcpListener.cs @@ -90,6 +90,45 @@ public void Stop() Tcp.RemoveConnection(StateMachine.LocalEndPoint.Port, StateMachine.RemoteEndPoint.Port, StateMachine.LocalEndPoint.Address, StateMachine.RemoteEndPoint.Address); StateMachine = null; } + else if (StateMachine.Status == Status.ESTABLISHED) + { + StateMachine.SendEmptyPacket(Flags.FIN | Flags.ACK); + + StateMachine.TCB.SndNxt++; + + StateMachine.Status = Status.FIN_WAIT1; + + if (StateMachine.WaitStatus(Status.CLOSED, 5000) == false) + { + throw new Exception("Failed to close TCP connection!"); + } + + Tcp.RemoveConnection(StateMachine.LocalEndPoint.Port, StateMachine.RemoteEndPoint.Port, StateMachine.LocalEndPoint.Address, StateMachine.RemoteEndPoint.Address); + } + } + + /// + /// Returns a value whether the TCP server is waiting for a connection + /// + public bool IsListening() + { + return StateMachine.Status == Status.LISTEN; + } + + /// + /// Returns a value whether the TCP server is connected to a remote host. + /// + public bool IsConnected() + { + return StateMachine.Status == Status.ESTABLISHED; + } + + /// + /// Returns a value whether the TCP server is closed + /// + public bool IsClosed() + { + return StateMachine == null || StateMachine.Status == Status.CLOSED; } public void Dispose() diff --git a/source/Cosmos.System2/Network/IPv4/UDP/DHCP/DHCPAck.cs b/source/Cosmos.System2/Network/IPv4/UDP/DHCP/DHCPAck.cs deleted file mode 100644 index d8741e61a6..0000000000 --- a/source/Cosmos.System2/Network/IPv4/UDP/DHCP/DHCPAck.cs +++ /dev/null @@ -1,57 +0,0 @@ -namespace Cosmos.System.Network.IPv4.UDP.DHCP -{ - /// - /// Represents a DHCP acknowledge (ACK) packet. - /// - internal class DHCPAck : DHCPPacket - { - /// - /// Initializes a new instance of the class. - /// - internal DHCPAck() : base() - { } - - /// - /// Initializes a new instance of the class. - /// - /// Raw data. - internal DHCPAck(byte[] rawData) : base(rawData) - { } - - protected override void InitializeFields() - { - base.InitializeFields(); - - foreach (var option in Options) - { - if (option.Type == 1) // Mask - { - Subnet = new Address(option.Data, 0); - } - else if (option.Type == 3) // Router - { - Server = new Address(option.Data, 0); - } - else if (option.Type == 6) // DNS - { - DNS = new Address(option.Data, 0); - } - } - } - - /// - /// Gets the subnet IPv4 address. - /// - internal Address Subnet { get; private set; } - - /// - /// Gets the DNS IPv4 address. - /// - internal Address DNS { get; private set; } - - /// - /// Gets the DHCP server IPv4 address. - /// - internal Address Server { get; private set; } - } -} diff --git a/source/Cosmos.System2/Network/IPv4/UDP/DHCP/DHCPClient.cs b/source/Cosmos.System2/Network/IPv4/UDP/DHCP/DHCPClient.cs index 9a9fd9d523..a4ff6d2ec8 100644 --- a/source/Cosmos.System2/Network/IPv4/UDP/DHCP/DHCPClient.cs +++ b/source/Cosmos.System2/Network/IPv4/UDP/DHCP/DHCPClient.cs @@ -1,5 +1,15 @@ -using System; +/* +* PROJECT: Aura Operating System Development +* CONTENT: DHCP - DHCP Core +* PROGRAMMER(S): Alexy DA CRUZ +* Valentin CHARBONNIER +*/ + +using Cosmos.System.Network.IPv4; +using System; +using Cosmos.System.Network.IPv4.UDP.DNS; using Cosmos.System.Network.Config; +using System.Collections.Generic; using Cosmos.HAL; namespace Cosmos.System.Network.IPv4.UDP.DHCP @@ -9,7 +19,10 @@ namespace Cosmos.System.Network.IPv4.UDP.DHCP /// public class DHCPClient : UdpClient { - private bool asked = false; + /// + /// Is DHCP ascked check variable + /// + private bool applied = false; /// /// Gets the IP address of the DHCP server. @@ -28,6 +41,12 @@ public DHCPClient() : base(68) { } + /// + /// Receive data + /// + /// timeout value, default 5000ms + /// time value (-1 = timeout) + /// Thrown on fatal error (contact support). private int Receive(int timeout = 5000) { int second = 0; @@ -48,23 +67,20 @@ private int Receive(int timeout = 5000) var packet = new DHCPPacket(rxBuffer.Dequeue().RawData); - if (packet.MessageType == 2) // Boot Reply + if (packet.MessageType == 2) //Boot Reply { - if (packet.RawData[284] == 0x02) // Offer packet received + if (packet.RawData[284] == 0x02) //Offer packet received { NetworkStack.Debugger.Send("Offer received."); return SendRequestPacket(packet.Client); } - else if (packet.RawData[284] is 0x05 or 0x06) // ACK or NAK DHCP packet received + else if (packet.RawData[284] == 0x05 || packet.RawData[284] == 0x06) //ACK or NAK DHCP packet received { - var ack = new DHCPAck(packet.RawData); - if (asked) - { - Apply(ack, true); - } - else + if (applied == false) { - Apply(ack); + Apply(packet, true); + + Close(); } } } @@ -110,7 +126,7 @@ public int SendDiscoverPacket() OutgoingBuffer.AddPacket(dhcpDiscover); NetworkStack.Update(); - asked = true; + applied = false; } return Receive(); @@ -139,45 +155,44 @@ private int SendRequestPacket(Address requestedAddress) /// /// Enable/Disable the displaying of messages about DHCP applying and conf. Disabled by default. /// - private void Apply(DHCPAck packet, bool message = false) + private void Apply(DHCPPacket packet, bool message = false) { - NetworkStack.RemoveAllConfigIP(); - - //cf. Roadmap. (have to change this, because some network interfaces are not configured in dhcp mode) [have to be done in 0.5.x] - foreach (NetworkDevice networkDevice in NetworkDevice.Devices) + if (applied == false) { - // NOTE: @ascpixi: Why are we checking if ToString() returns null - // *four* times...? Can this be removed? - if (packet.Client.ToString() == null || - packet.Client.ToString() == null || - packet.Client.ToString() == null || - packet.Client.ToString() == null) - { - throw new Exception("Parsing DHCP ACK Packet failed, can't apply network configuration."); - } - else + NetworkStack.RemoveAllConfigIP(); + + //cf. Roadmap. (have to change this, because some network interfaces are not configured in dhcp mode) [have to be done in 0.5.x] + foreach (NetworkDevice networkDevice in NetworkDevice.Devices) { - if (message) + if (packet.Client.ToString() == null) { - NetworkStack.Debugger.Send("[DHCP ACK][" + networkDevice.Name + "] Packet received, applying IP configuration..."); - NetworkStack.Debugger.Send(" IP Address : " + packet.Client.ToString()); - NetworkStack.Debugger.Send(" Subnet mask : " + packet.Subnet.ToString()); - NetworkStack.Debugger.Send(" Gateway : " + packet.Server.ToString()); - NetworkStack.Debugger.Send(" DNS server : " + packet.DNS.ToString()); + throw new Exception("Parsing DHCP ACK Packet failed, can't apply network configuration."); } + else + { + HAL.Global.debugger.Send("[DHCP ACK][" + networkDevice.Name + "] Packet received, applying IP configuration..."); + HAL.Global.debugger.Send(" IP Address : " + packet.Client.ToString()); + HAL.Global.debugger.Send(" Subnet mask : " + packet.Subnet.ToString()); + HAL.Global.debugger.Send(" Gateway : " + packet.Server.ToString()); + HAL.Global.debugger.Send(" DNS server : " + packet.DNS.ToString()); - IPConfig.Enable(networkDevice, packet.Client, packet.Subnet, packet.Server); - DNSConfig.Add(packet.DNS); + IPConfig.Enable(networkDevice, packet.Client, packet.Subnet, packet.Server); + DNSConfig.Add(packet.DNS); - if (message) - { - NetworkStack.Debugger.Send("[DHCP CONFIG][" + networkDevice.Name + "] IP configuration applied."); - asked = false; + HAL.Global.debugger.Send("[DHCP CONFIG][" + networkDevice.Name + "] IP configuration applied."); + + applied = true; + + return; } } - } - Close(); + HAL.Global.debugger.Send("[DHCP CONFIG] No DHCP Config applied!"); + } + else + { + HAL.Global.debugger.Send("[DHCP CONFIG] DHCP already applied."); + } } } -} +} \ No newline at end of file diff --git a/source/Cosmos.System2/Network/IPv4/UDP/DHCP/DHCPPacket.cs b/source/Cosmos.System2/Network/IPv4/UDP/DHCP/DHCPPacket.cs index c54d57e572..b27ac7cf30 100644 --- a/source/Cosmos.System2/Network/IPv4/UDP/DHCP/DHCPPacket.cs +++ b/source/Cosmos.System2/Network/IPv4/UDP/DHCP/DHCPPacket.cs @@ -1,6 +1,17 @@ -using Cosmos.HAL.Network; +/* +* PROJECT: Aura Operating System Development +* CONTENT: DHCP Packet +* PROGRAMMERS: Alexy DA CRUZ +* Valentin CHARBONNIER +*/ + +using Cosmos.HAL; +using Cosmos.HAL.Network; +using Cosmos.System.Network.IPv4; +using Cosmos.System.Network.IPv4.UDP; using System; using System.Collections.Generic; +using System.Text; namespace Cosmos.System.Network.IPv4.UDP.DHCP { @@ -41,6 +52,7 @@ public class DHCPPacket : UDPPacket public static void DHCPHandler(byte[] packetData) { var dhcpPacket = new DHCPPacket(packetData); + var receiver = UdpClient.GetClient(dhcpPacket.DestinationPort); receiver?.ReceiveData(dhcpPacket); } @@ -134,11 +146,19 @@ internal DHCPPacket(Address client, Address server, MACAddress sourceMAC, ushort InitializeFields(); } + /// + /// Init DHCPPacket fields. + /// + /// Thrown if RawData is invalid or null. protected override void InitializeFields() { base.InitializeFields(); MessageType = RawData[42]; - Client = new Address(RawData, 58); + + if (RawData[58] != 0) + { + Client = new Address(RawData, 58); + } if (RawData[282] != 0) { @@ -158,6 +178,22 @@ protected override void InitializeFields() i += option.Length; } + + foreach (var option in Options) + { + if (option.Type == 1) //Mask + { + Subnet = new Address(option.Data, 0); + } + else if (option.Type == 3) //Router + { + Server = new Address(option.Data, 0); + } + else if (option.Type == 6) //DNS + { + DNS = new Address(option.Data, 0); + } + } } } @@ -175,5 +211,20 @@ protected override void InitializeFields() /// Gets the DHCP options. /// internal List Options { get; private set; } + + /// + /// Get Subnet IPv4 Address + /// + internal Address Subnet { get; private set; } + + /// + /// Get DNS IPv4 Address + /// + internal Address DNS { get; private set; } + + /// + /// Get DHCP Server IPv4 Address + /// + internal Address Server { get; private set; } } -} +} \ No newline at end of file