Added routing via default gateways to TCP/IP Stack

Added outgoing TCP connection support to TcpClient
Added disconnect event and Closing down of TCP connections to TcpClient
This commit is contained in:
sschocke_cp 2009-04-04 19:55:13 +00:00
parent e42825c450
commit cc0fa5a4cc
4 changed files with 200 additions and 5 deletions

View file

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

View file

@ -27,6 +27,12 @@ namespace Cosmos.Sys.Network
/// <param name="data">Byte buffer of the received data</param>
public delegate void ClientDataReceived(TcpClient client, byte[] data);
/// <summary>
/// TCP Client disconnection delegate
/// </summary>
/// <param name="client">Instance of the <see cref="TcpClient"/> that represents the connection</param>
public delegate void ClientDisconnected(TcpClient client);
/// <summary>
/// Implements a TCP/IP Stack on top of Cosmos
/// </summary>
@ -38,7 +44,7 @@ namespace Cosmos.Sys.Network
private static List<IPv4Config> ipConfigs;
private static HW.TempDictionary<DataReceived> udpClients;
private static HW.TempDictionary<ClientConnected> tcpListeners;
private static List<TCP.TCPConnection> tcpSockets;
internal static List<TCP.TCPConnection> tcpSockets;
/// <summary>
/// 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;
}
}
}

View file

@ -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; }
}
/// <summary>
/// Data Received callback function
/// </summary>
public ClientDisconnected Disconnect
{
get { return this.disconnectCallback; }
set { this.disconnectCallback = value; }
}
/// <summary>
/// Send a string to the remote host
/// </summary>
@ -52,6 +83,18 @@ namespace Cosmos.Sys.Network
TCPIP.IPv4OutgoingBuffer.AddPacket(packet);
}
/// <summary>
/// Close down an active connection
/// </summary>
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; }
}
/// <summary>
/// Returns true if the current connection is active
/// </summary>
public bool Connected
{
get { return (this.connection.ConnectionState == TCPConnection.State.ESTABLISHED); }
}
internal void disconnect()
{
if (this.disconnectCallback != null)
{
this.disconnectCallback(this);
}
}
}
}

View file

@ -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 = "<html><body><h1>It works! This is a web page being hosted by your Cosmos Operating System</h1></body></html>";
int webPageLength = webPage.Length;
@ -69,9 +76,15 @@ namespace Cosmos.Playground.SSchocke {
error404 += "<html><body>404 URL Not found</html>";
#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();
}
}
}