diff --git a/source/Cosmos/Cosmos.System/Network/TCPIP/IPv4OutgoingBuffer.cs b/source/Cosmos/Cosmos.System/Network/TCPIP/IPv4OutgoingBuffer.cs
index 18a5c2b96..ea3b43dec 100644
--- a/source/Cosmos/Cosmos.System/Network/TCPIP/IPv4OutgoingBuffer.cs
+++ b/source/Cosmos/Cosmos.System/Network/TCPIP/IPv4OutgoingBuffer.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using HW = Cosmos.Hardware;
+using System;
namespace Cosmos.Sys.Network.TCPIP
{
@@ -7,11 +8,12 @@ namespace Cosmos.Sys.Network.TCPIP
{
private class BufferEntry
{
- public enum EntryStatus { ADDED, ARP_SENT, DONE };
+ public enum EntryStatus { ADDED, ARP_SENT, ROUTE_ARP_SENT, JUST_SEND, DONE };
public HW.Network.NetworkDevice NIC;
public IPPacket Packet;
public EntryStatus Status;
+ public IPv4Address nextHop;
public BufferEntry(HW.Network.NetworkDevice nic, IPPacket packet)
{
@@ -53,6 +55,35 @@ namespace Cosmos.Sys.Network.TCPIP
BufferEntry entry = queue[e];
if (entry.Status == BufferEntry.EntryStatus.ADDED)
{
+ if (TCPIPStack.IsLocalAddress(entry.Packet.DestinationIP) == false)
+ {
+ entry.nextHop = TCPIPStack.FindRoute(entry.Packet.DestinationIP);
+ if (entry.nextHop == null)
+ {
+ entry.Status = BufferEntry.EntryStatus.DONE;
+ continue;
+ }
+
+ if (ARP.ARPCache.Contains(entry.nextHop) == true)
+ {
+ entry.Packet.DestinationMAC = ARP.ARPCache.Resolve(entry.nextHop);
+
+ entry.NIC.QueueBytes(entry.Packet.RawData);
+
+ entry.Status = BufferEntry.EntryStatus.DONE;
+ }
+ else
+ {
+ ARP.ARPRequest_EthernetIPv4 arp_request = new ARP.ARPRequest_EthernetIPv4(entry.NIC.MACAddress, entry.Packet.SourceIP,
+ HW.Network.MACAddress.Broadcast, entry.nextHop);
+
+ entry.NIC.QueueBytes(arp_request.RawData);
+
+ entry.Status = BufferEntry.EntryStatus.ROUTE_ARP_SENT;
+ }
+ continue;
+ }
+
if (ARP.ARPCache.Contains(entry.Packet.DestinationIP) == true)
{
entry.Packet.DestinationMAC = ARP.ARPCache.Resolve(entry.Packet.DestinationIP);
@@ -71,6 +102,12 @@ namespace Cosmos.Sys.Network.TCPIP
entry.Status = BufferEntry.EntryStatus.ARP_SENT;
}
}
+ else if (entry.Status == BufferEntry.EntryStatus.JUST_SEND)
+ {
+ entry.NIC.QueueBytes(entry.Packet.RawData);
+
+ entry.Status = BufferEntry.EntryStatus.DONE;
+ }
}
int i = 0;
@@ -100,7 +137,16 @@ namespace Cosmos.Sys.Network.TCPIP
{
entry.Packet.DestinationMAC = arp_reply.SenderMAC;
- entry.Status = BufferEntry.EntryStatus.ADDED;
+ entry.Status = BufferEntry.EntryStatus.JUST_SEND;
+ }
+ }
+ else if (entry.Status == BufferEntry.EntryStatus.ROUTE_ARP_SENT)
+ {
+ if (entry.nextHop.CompareTo(arp_reply.SenderIP) == 0)
+ {
+ entry.Packet.DestinationMAC = arp_reply.SenderMAC;
+
+ entry.Status = BufferEntry.EntryStatus.JUST_SEND;
}
}
}
diff --git a/source/Cosmos/Cosmos.System/Network/TCPIPStack.cs b/source/Cosmos/Cosmos.System/Network/TCPIPStack.cs
index e0dc98619..e39831e72 100644
--- a/source/Cosmos/Cosmos.System/Network/TCPIPStack.cs
+++ b/source/Cosmos/Cosmos.System/Network/TCPIPStack.cs
@@ -27,6 +27,12 @@ namespace Cosmos.Sys.Network
/// Byte buffer of the received data
public delegate void ClientDataReceived(TcpClient client, byte[] data);
+ ///
+ /// TCP Client disconnection delegate
+ ///
+ /// Instance of the that represents the connection
+ public delegate void ClientDisconnected(TcpClient client);
+
///
/// Implements a TCP/IP Stack on top of Cosmos
///
@@ -38,7 +44,7 @@ namespace Cosmos.Sys.Network
private static List ipConfigs;
private static HW.TempDictionary udpClients;
private static HW.TempDictionary tcpListeners;
- private static List tcpSockets;
+ internal static List tcpSockets;
///
/// Initialize the TCP/IP Stack variables
@@ -244,6 +250,19 @@ namespace Cosmos.Sys.Network
active_connection.ConnectionState = TCP.TCPConnection.State.ESTABLISHED;
}
}
+ else if (active_connection.ConnectionState == TCP.TCPConnection.State.SYN_SENT)
+ {
+ if ((tcp_packet.Syn == true) && (tcp_packet.Ack == true) && ((active_connection.LocalSequenceNumber + 1) == tcp_packet.AckNumber))
+ {
+ active_connection.LocalSequenceNumber++;
+ active_connection.RemoteSequenceNumber = tcp_packet.SequenceNumber + 1;
+ active_connection.ConnectionState = TCP.TCPConnection.State.ESTABLISHED;
+
+ TCP.TCPPacket ack = new TCP.TCPPacket(active_connection, active_connection.LocalSequenceNumber,
+ active_connection.RemoteSequenceNumber, 0x10, 8192);
+ TCPIP.IPv4OutgoingBuffer.AddPacket(ack);
+ }
+ }
else if (active_connection.ConnectionState == TCP.TCPConnection.State.ESTABLISHED)
{
if (tcp_packet.Ack == true)
@@ -261,6 +280,11 @@ namespace Cosmos.Sys.Network
active_connection.client.dataReceived(tcp_packet.TCP_Data);
}
+
+ if (tcp_packet.Fin == true)
+ {
+ active_connection.client.disconnect();
+ }
}
}
@@ -354,5 +378,32 @@ namespace Cosmos.Sys.Network
return default_gw;
}
+
+ internal static bool IsLocalAddress(IPv4Address destIP)
+ {
+ for (int c = 0; c < ipConfigs.Count; c++)
+ {
+ if ((ipConfigs[c].IPAddress.To32BitNumber() & ipConfigs[c].SubnetMask.To32BitNumber()) ==
+ (destIP.To32BitNumber() & ipConfigs[c].SubnetMask.To32BitNumber()))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ internal static IPv4Address FindRoute(IPv4Address destIP)
+ {
+ for (int c = 0; c < ipConfigs.Count; c++)
+ {
+ if (ipConfigs[c].DefaultGateway.CompareTo(IPv4Address.Zero) != 0)
+ {
+ return ipConfigs[c].DefaultGateway;
+ }
+ }
+
+ return null;
+ }
}
}
diff --git a/source/Cosmos/Cosmos.System/Network/TcpClient.cs b/source/Cosmos/Cosmos.System/Network/TcpClient.cs
index c7f46546c..b8269fb65 100644
--- a/source/Cosmos/Cosmos.System/Network/TcpClient.cs
+++ b/source/Cosmos/Cosmos.System/Network/TcpClient.cs
@@ -1,4 +1,5 @@
using Cosmos.Sys.Network.TCPIP.TCP;
+using System;
namespace Cosmos.Sys.Network
{
@@ -9,6 +10,27 @@ namespace Cosmos.Sys.Network
{
internal TCPConnection connection;
internal ClientDataReceived dataCallback;
+ internal ClientDisconnected disconnectCallback;
+
+ protected static UInt16 NextLocalPort = 33000;
+
+ public TcpClient(IPv4Address dest, UInt16 port)
+ {
+ IPv4Address source = TCPIPStack.FindNetwork(dest);
+ if( source == null )
+ {
+ throw new ArgumentException("Destination host unreachable", "dest");
+ }
+
+ this.connection = new TCPConnection(dest, port, source, NextLocalPort++, 0x5656, TCPConnection.State.SYN_SENT);
+ this.connection.client = this;
+
+ TCPIPStack.tcpSockets.Add(connection);
+
+ TCPPacket packet = new TCPPacket(connection, connection.LocalSequenceNumber, 0, 0x02, 8192);
+
+ TCPIP.IPv4OutgoingBuffer.AddPacket(packet);
+ }
internal TcpClient(TCPConnection connection)
{
@@ -25,6 +47,15 @@ namespace Cosmos.Sys.Network
set { this.dataCallback = value; }
}
+ ///
+ /// Data Received callback function
+ ///
+ public ClientDisconnected Disconnect
+ {
+ get { return this.disconnectCallback; }
+ set { this.disconnectCallback = value; }
+ }
+
///
/// Send a string to the remote host
///
@@ -52,6 +83,18 @@ namespace Cosmos.Sys.Network
TCPIP.IPv4OutgoingBuffer.AddPacket(packet);
}
+ ///
+ /// Close down an active connection
+ ///
+ public void Close()
+ {
+ TCPPacket packet = new TCPPacket(connection, connection.LocalSequenceNumber, connection.RemoteSequenceNumber, 0x11, 8192);
+
+ TCPIP.IPv4OutgoingBuffer.AddPacket(packet);
+
+ connection.ConnectionState = TCPConnection.State.TIMEWAIT;
+ }
+
internal void dataReceived(byte[] data)
{
if (this.dataCallback != null)
@@ -74,5 +117,21 @@ namespace Cosmos.Sys.Network
{
get { return this.connection.LocalEndpoint; }
}
+
+ ///
+ /// Returns true if the current connection is active
+ ///
+ public bool Connected
+ {
+ get { return (this.connection.ConnectionState == TCPConnection.State.ESTABLISHED); }
+ }
+
+ internal void disconnect()
+ {
+ if (this.disconnectCallback != null)
+ {
+ this.disconnectCallback(this);
+ }
+ }
}
}
diff --git a/source/SSchockeTest/Program.cs b/source/SSchockeTest/Program.cs
index 1db33fcda..eaf5f03a6 100644
--- a/source/SSchockeTest/Program.cs
+++ b/source/SSchockeTest/Program.cs
@@ -46,11 +46,18 @@ namespace Cosmos.Playground.SSchocke {
Console.WriteLine("Initializing TCP Stack...");
TCPIPStack.Init();
- TCPIPStack.ConfigIP(nic, new IPv4Config(new IPv4Address(192, 168, 21, 123), new IPv4Address(255, 255, 255, 0)));
+ TCPIPStack.ConfigIP(nic, new IPv4Config(new IPv4Address(192, 168, 20, 123),
+ new IPv4Address(255, 255, 255, 0),
+ new IPv4Address(192, 168, 20, 100)));
Console.WriteLine("Initializing TCP Port 80...");
TCPIPStack.AddTcpListener(80, WebServerConnect);
+ Console.WriteLine("Setup outgoing connection...");
+ TcpClient webClient = new TcpClient(new IPv4Address(196, 38, 235, 2), 80);
+ webClient.DataReceived = WebClient_RecvData;
+ webClient.Disconnect = WebClientDisconnect;
+
#region Setup WebServer strings
webPage = "It works! This is a web page being hosted by your Cosmos Operating System
";
int webPageLength = webPage.Length;
@@ -69,9 +76,15 @@ namespace Cosmos.Playground.SSchocke {
error404 += "404 URL Not found";
#endregion
+ bool requestDone = false;
while (true)
{
TCPIPStack.Update();
+ if ((requestDone == false) && (webClient.Connected == true))
+ {
+ webClient.SendString("GET /\r\n");
+ requestDone = true;
+ }
}
Console.WriteLine("Press a key to shutdown...");
@@ -83,6 +96,13 @@ namespace Cosmos.Playground.SSchocke {
{
Console.WriteLine("Client(" + client.RemoteEndpoint.ToString() + ") Connected to port 80...");
client.DataReceived = WebServer_RecvData;
+ client.Disconnect = WebServerDisconnect;
+ }
+
+ private static void WebServerDisconnect(TcpClient client)
+ {
+ Console.WriteLine("Client(" + client.RemoteEndpoint.ToString() + ") disconnected...");
+ client.Close();
}
private static void WebServer_RecvData(TcpClient client, byte[] data)
@@ -104,5 +124,24 @@ namespace Cosmos.Playground.SSchocke {
client.SendString(error404);
}
}
- }
+
+ private static void WebClient_RecvData(TcpClient client, byte[] data)
+ {
+ Console.WriteLine("Received reply from " + client.RemoteEndpoint.ToString());
+ StringBuilder sb = new StringBuilder(data.Length);
+ for (int b = 0; b < data.Length; b++)
+ {
+ sb.Append((char)data[b]);
+ }
+ String dataString = sb.ToString();
+
+ Console.WriteLine(dataString);
+ }
+
+ private static void WebClientDisconnect(TcpClient client)
+ {
+ Console.WriteLine("Disconnect from " + client.RemoteEndpoint.ToString() + "...");
+ client.Close();
+ }
+ }
}
\ No newline at end of file