219 lines
7.1 KiB
C#
219 lines
7.1 KiB
C#
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Microsoft Research, Cambridge
|
|
* author: Yaron Weinsberg, Richard Black
|
|
*/
|
|
|
|
using NetStack.Common;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Diagnostics;
|
|
|
|
#if !SINGULARITY
|
|
using System.Net;
|
|
using System.Text;
|
|
#endif
|
|
|
|
using System.Net.IP;
|
|
using Drivers.Net;
|
|
using NetStack.Protocols;
|
|
|
|
namespace NetStack.Runtime
|
|
{
|
|
/**
|
|
* This module implements the TCP protocol
|
|
* Notice: It is a simplified implementation (the very basic)
|
|
*/
|
|
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)
|
|
{
|
|
Debug.Assert(parameters == null || parameters["name"]=="TCP");
|
|
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();
|
|
Core.Instance().RegisterSession(this,tcp);
|
|
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)
|
|
{
|
|
DebugPrint("TcpModule.OnPacketReceive\n");
|
|
|
|
// 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;
|
|
if (!TcpFormat.ReadTcpHeader(packet, out tcpHeader))
|
|
{
|
|
DebugPrint("Bad TCP Header");
|
|
return NetStatus.Code.PROTOCOL_DROP_ERROR;
|
|
}
|
|
|
|
// check validity
|
|
if (tcpHeader.checksum != 0 &&
|
|
TcpFormat.IsChecksumValid(ipHeader,tcpHeader, packet) == false)
|
|
{
|
|
DebugPrint("TCP checksum failed. No cigar and no packet!");
|
|
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...
|
|
Session s = FindSession(ipHeader, ref tcpHeader);
|
|
if (s != null) {
|
|
DebugPrint("TCP Session found.\n");
|
|
// deliver the packet the the session
|
|
// we pass the tcpHeader as a context
|
|
// and the ipHeader as a packet.OverlapContext
|
|
// since we will not use it anymore (and TCP may need it)
|
|
packet.OverlapContext = ipHeader;
|
|
return s.OnReceive(this,packet,tcpHeader);
|
|
}
|
|
|
|
return NetStatus.Code.PROTOCOL_DROP_ERROR;
|
|
}
|
|
|
|
// find the relevant session for this connection
|
|
protected Session FindSession(IPFormat.IPHeader! ipHeader,
|
|
ref TcpFormat.TcpHeader tcpHeader)
|
|
{
|
|
// get the session table
|
|
ArrayList sessions = Core.Instance().GetSessions(this);
|
|
if (sessions == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
TcpSession passiveSession = null; // this is the passive session
|
|
// we first look for full match, saving the passive session
|
|
// if exist. if no full match, we return the passiveSession
|
|
|
|
lock (sessions.SyncRoot)
|
|
{
|
|
// this is a TcpSession
|
|
foreach(TcpSession! s in sessions)
|
|
{
|
|
bool b1 = (s.LocalAddress == ipHeader.Destination);
|
|
bool b2 = (s.RemoteAddress == ipHeader.Source);
|
|
bool b3 = (s.LocalPort == tcpHeader.destPort);
|
|
bool b4 = (s.RemotePort == tcpHeader.sourcePort);
|
|
|
|
bool fullMatch = b1 & b2 & b3 & b4;
|
|
// if we have full match, we return
|
|
// otherwise, save the passive session
|
|
if (fullMatch)
|
|
{
|
|
return s;
|
|
}
|
|
bool b5 = (s.RemoteAddress == IPv4.Broadcast &&
|
|
s.RemotePort == 0);
|
|
bool passiveMatch = b1 & b3 & b5;
|
|
if (passiveMatch)
|
|
{
|
|
passiveSession = s;
|
|
}
|
|
}
|
|
}
|
|
// if we can't find exact match...
|
|
return passiveSession;
|
|
}
|
|
// this method send a ready made TCP packet,
|
|
// it uses the IP layer.
|
|
public NetStatus OnProtocolSend(NetPacket! pkt)
|
|
{
|
|
// if the ARP hasn't resolved the address yet, the
|
|
// runtime will try this again (on the next handle
|
|
// of outgoing sessions' queues)
|
|
return ip.OnProtocolSend(pkt);
|
|
}
|
|
|
|
public NetStatus SetProtocolSpecific(ushort opcode, byte[]! data)
|
|
{
|
|
return NetStatus.Code.PROTOCOL_OK;
|
|
}
|
|
|
|
public NetStatus GetProtocolSpecific(ushort opcode,out byte[] data)
|
|
{
|
|
data=null;
|
|
return NetStatus.Code.PROTOCOL_OK;
|
|
}
|
|
|
|
public TcpModule()
|
|
{
|
|
}
|
|
}
|
|
}
|