singrdk/base/Services/NetStack/Runtime/TCPModule.cs

235 lines
8.3 KiB
C#
Raw Normal View History

2008-11-17 18:29:00 -05:00
// ----------------------------------------------------------------------------
2008-03-05 09:52:00 -05:00
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
2008-11-17 18:29:00 -05:00
// ----------------------------------------------------------------------------
2008-03-05 09:52:00 -05:00
2008-11-17 18:29:00 -05:00
// #define DEBUG_TCP
///
// Microsoft Research, Cambridge
//
2008-03-05 09:52:00 -05:00
using System;
using System.Collections;
using System.Diagnostics;
2008-11-17 18:29:00 -05:00
using System.Net.IP;
2008-03-05 09:52:00 -05:00
#if !SINGULARITY
using System.Net;
using System.Text;
#endif
using Drivers.Net;
2008-11-17 18:29:00 -05:00
using NetStack.Common;
2008-03-05 09:52:00 -05:00
using NetStack.Protocols;
namespace NetStack.Runtime
{
2008-11-17 18:29:00 -05:00
///
// This module implements the TCP protocol
// Notice: It is a simplified implementation (the very basic)
//
2008-03-05 09:52:00 -05:00
public class TcpModule : IProtocol
{
// the ip handler
protected IProtocol ip;
// the TCP retransmit timeout
protected int retransTimeout;
// INetModule interfaces
// ------------------------
string INetModule.ModuleName { get { return "TCP"; } }
ushort INetModule.ModuleVersion { get { return 0x01; } } // 0.1
public bool StartModule()
{
#if DEBUG_TCP
Core.Log("Starting TCP module...\n");
#endif
ip = Core.Instance().GetProtocolByName("IP");
Debug.Assert(ip != null);
return true;
}
public bool StopModule()
{
return true;
}
public bool DestroyModule()
{
return true;
}
// IProtocol interfaces
// ------------------------
public bool Initialize(ProtocolParams parameters)
{
2008-11-17 18:29:00 -05:00
Debug.Assert(parameters == null || parameters["name"] == "TCP");
2008-03-05 09:52:00 -05:00
Core.Instance().RegisterProtocol(this);
TcpSessionPool.SetTcpModule(this);
return true;
}
[ Conditional("DEBUG_TCP") ]
private static void DebugPrint(string format, params object [] args)
{
Core.Log(format, args);
}
public ushort GetProtocolID()
{
return ((ushort)IPFormat.Protocol.TCP);
}
Session IProtocol.CreateSession()
{
TcpSession tcp = (TcpSession) TcpSessionPool.Get();
2008-11-17 18:29:00 -05:00
Core.Instance().RegisterSession(this, tcp);
2008-03-05 09:52:00 -05:00
return tcp;
}
public TcpSession! ReInitializeSession(TcpSession! tcp)
{
tcp.ReInitialize(this);
Core.Instance().RegisterSession(this, tcp);
return tcp;
}
// handle incoming TCP packets
public NetStatus OnProtocolReceive(NetPacket! packet)
{
// IP should have passed us a context which
// is the IPHeader... lets see...
IPFormat.IPHeader! ipHeader = (IPFormat.IPHeader!) packet.OverlapContext;
// read the TCP header
TcpFormat.TcpHeader tcpHeader;
2008-11-17 18:29:00 -05:00
if (!TcpFormat.ReadTcpHeader(packet, out tcpHeader)) {
DebugPrint("Bad TCP Header. Packet rejected.");
2008-03-05 09:52:00 -05:00
return NetStatus.Code.PROTOCOL_DROP_ERROR;
}
// check validity
if (tcpHeader.checksum != 0 &&
TcpFormat.IsChecksumValid(ipHeader,tcpHeader, packet) == false)
{
2008-11-17 18:29:00 -05:00
DebugPrint("TCP checksum failed. Packet rejected.");
2008-03-05 09:52:00 -05:00
return NetStatus.Code.PROTOCOL_DROP_CHKSUM;
}
// where is our data?
// skip over options (that we currently ignore)
int tcpHeaderSize = 4 * TcpFormat.GetOffset(ref tcpHeader);
int startIndex = EthernetFormat.Size + IPFormat.Size + tcpHeaderSize;
int segmentSize = ipHeader.totalLength - IPFormat.Size - tcpHeaderSize;
packet.Clip(startIndex,segmentSize - 1);
// find the relevant session...
2008-11-17 18:29:00 -05:00
Session tcpSession = FindSession(ipHeader, ref tcpHeader);
if (tcpSession == null) {
DebugPrint("TCP Session not found. TCP Packet dropped.");
}
else {
// Deliver the packet to the session. The tpcHeader is passed
// as a context and the ipHeader is passed as a
// packet.OverlapContext since we will not use it anymore
// (and TCP may need it).
2008-03-05 09:52:00 -05:00
packet.OverlapContext = ipHeader;
2008-11-17 18:29:00 -05:00
return tcpSession.OnReceive(this, packet, tcpHeader);
2008-03-05 09:52:00 -05:00
}
return NetStatus.Code.PROTOCOL_DROP_ERROR;
}
2008-11-17 18:29:00 -05:00
// Find the relevant session for this connection
protected TcpSession FindSession(IPFormat.IPHeader! ipHeader,
ref TcpFormat.TcpHeader tcpHeader)
2008-03-05 09:52:00 -05:00
{
2008-11-17 18:29:00 -05:00
// Get the session table
2008-03-05 09:52:00 -05:00
ArrayList sessions = Core.Instance().GetSessions(this);
2008-11-17 18:29:00 -05:00
if (sessions == null) {
2008-03-05 09:52:00 -05:00
return null;
}
2008-11-17 18:29:00 -05:00
// First priority is a full match (Loc/Rem X Addr/Port all match),
// but next priority is a "passive" match (a Broadcast to "me").
2008-03-05 09:52:00 -05:00
TcpSession passiveSession = null; // this is the passive session
2008-11-17 18:29:00 -05:00
lock (sessions.SyncRoot) {
// BUGBUG: This should use HashTables (KeyedCollections // TODO
// BUGBUG: if we get Generics) for Performance reasons. // TODO
// BUGBUG: We need one for full and one for passive. // TODO
// BUGBUG: The full hashtable uses local and remote // TODO
// BUGBUG: addresses as the keys and can be limited to // TODO
// BUGBUG: sessions without Remote Broadcast addresses; // TODO
// BUGBUG: the passive hashtable is limited to sessions // TODO
// BUGBUG: with Remote Broadcast addresses and uses the // TODO
// BUGBUG: local address only as the key. // TODO
// BUGBUG: Note that this is done for every TCP Packet. // TODO
foreach (TcpSession! tcpSession in sessions) {
bool matchLocal =
(tcpSession.LocalAddress == ipHeader.Destination) &&
(tcpSession.LocalPort == tcpHeader.destPort);
// Both full and passive matches require full Local match.
if (matchLocal) {
// Check the Remote Match for a Full Match
bool matchRemote =
(tcpSession.RemoteAddress == ipHeader.Source) &&
(tcpSession.RemotePort == tcpHeader.sourcePort);
// If a full match (local && remote) return the session.
if (matchRemote) {
return tcpSession;
}
// Check for "Broadcast" address.
bool matchBroadcast =
(tcpSession.RemoteAddress == IPv4.Broadcast) &&
(tcpSession.RemotePort == 0);
// No full match, but save passiveSession
// if matchLocal && matchBroadcast.
if (matchBroadcast) {
passiveSession = tcpSession;
}
2008-03-05 09:52:00 -05:00
}
}
}
2008-11-17 18:29:00 -05:00
// If we didn't find an exact match, return
// the passive match, if any (may be null).
2008-03-05 09:52:00 -05:00
return passiveSession;
}
2008-11-17 18:29:00 -05:00
// Send TCP packet, constructed by the caller, using the IP layer.
public NetStatus OnProtocolSend(NetPacket! packet)
2008-03-05 09:52:00 -05:00
{
// if the ARP hasn't resolved the address yet, the
// runtime will try this again (on the next handle
// of outgoing sessions' queues)
2008-11-17 18:29:00 -05:00
return ip.OnProtocolSend(packet);
2008-03-05 09:52:00 -05:00
}
public NetStatus SetProtocolSpecific(ushort opcode, byte[]! data)
{
return NetStatus.Code.PROTOCOL_OK;
}
2008-11-17 18:29:00 -05:00
public NetStatus GetProtocolSpecific(ushort opcode, out byte[] data)
2008-03-05 09:52:00 -05:00
{
2008-11-17 18:29:00 -05:00
data = null;
2008-03-05 09:52:00 -05:00
return NetStatus.Code.PROTOCOL_OK;
}
public TcpModule()
{
}
}
}