-- File: TcpUtilImpl.mesa - last edit:
-- JAV 19-Nov-87 14:04:54
-- AOF 2-Jun-87 12:18:06
-- sma 9-Feb-87 14:51:11
-- Copyright (C) 1985, 1986, 1987 by Xerox Corporation. All rights reserved.
DIRECTORY
ArpaBuffer USING [Body, Buffer],
ArpaPort USING [
GetAssignedAddress, GetBufferPool, SetIPLengths, SetWaitTime, WaitTime],
ArpaPortInternal USING [AddrMismatch, BuildMasks, GetSubnetMask],
ArpaRouter USING [InternetAddress, Port, unknownInternetAddress],
ArpaTypes USING [InternetAddress, Port],
CommUtil USING [PulsesToTicks],
Environment USING [Block, bytesPerPage, bytesPerWord],
File USING [nullFile],
Process USING [DisableTimeout, EnableAborts, MsecToTicks, SetTimeout],
Protocol1 USING [GetFamilyUnit],
Runtime USING [GetCaller],
Space USING [Map],
System USING [GetClockPulses, MicrosecondsToPulses],
TcpImpl USING [connection, rcvr, rexmtr, xmtr],
TcpPort USING [CreateTcpPort],
TcpStream USING [Precedence, Security, WaitTime],
TcpStreamInternal USING [
LowHalf, inputSpacePages, rcvrDefaults, rexmtrDefaults, maxTcpDataBytes,
xmtrAlloc, send, receive, tos, ttl, fragAllowed, minTcpHeaderBytes];
TcpUtilImpl: MONITOR
IMPORTS
ArpaPort, ArpaPortInternal, ArpaRouter, CommUtil, Process, Protocol1, Runtime,
Space, System, TcpPort, TcpStreamInternal
EXPORTS ArpaRouter, TcpStreamInternal =
BEGIN
seed: WORD ← TcpStreamInternal.LowHalf[System.GetClockPulses[]];
Port: PUBLIC --ArpaRouter-- TYPE = ArpaTypes.Port;
InternetAddress: PUBLIC --ArpaRouter-- TYPE = ArpaTypes.InternetAddress;
bpp: NATURAL = Environment.bytesPerPage;
bpw: NATURAL = Environment.bytesPerWord;
InitStream: PUBLIC PROC [local, remote: ArpaRouter.InternetAddress,
localPort, remotePort: ArpaRouter.Port, timeout: TcpStream.WaitTime,
precedence: TcpStream.Precedence, security: TcpStream.Security,
options: Environment.Block] =
BEGIN
time: LONG CARDINAL = System.GetClockPulses[];
mask: InternetAddress = ArpaPortInternal.BuildMasks[local].netMask;
-- set based on whether these guys are on the same network
delayToRemote: CARDINAL =
IF ArpaPortInternal.AddrMismatch[
IF ArpaPortInternal.GetSubnetMask[] # ArpaRouter.unknownInternetAddress THEN ArpaPortInternal.GetSubnetMask[] ELSE mask, local, remote]
THEN 1 ELSE 0;
him: LONG POINTER TO FRAME[TcpImpl] = LOOPHOLE[Runtime.GetCaller[]];
him.rcvr.nextSeq ← 0;
him.rcvr.maxSeq ← him.rcvr.irs ← 0;
--set for real when connection request arrives.
him.rcvr.ackInterval ←
System.MicrosecondsToPulses[LONG[1000] * LONG[
TcpStreamInternal.rcvrDefaults.ackInterval]];
him.rcvr.remoteBlocked ← FALSE;
him.rcvr.urgSig ← FALSE; --ditto.
him.rcvr.urg ← 0;
Process.EnableAborts[@him.rcvr.urgArrived];
Process.DisableTimeout[@him.rcvr.urgArrived];
him.rcvr.pushSig ← FALSE;
him.rcvr.push ← 0; --ditto.
him.rcvr.finSig ← FALSE;
him.rcvr.fin ← 0; --ditto.
him.rcvr.lastConsumed ← 0;
him.rcvr.inputSpace.size ←
(bpp * TcpStreamInternal.inputSpacePages) -
((bpp * TcpStreamInternal.inputSpacePages) MOD
TcpStreamInternal.maxTcpDataBytes);
him.rcvr.inputSpace.space ←
Space.Map[[File.nullFile, 0, TcpStreamInternal.inputSpacePages]];
him.rcvr.inuse ← [NIL, 0];
him.rcvr.avail ← [NIL, 0];
him.rcvr.process ← NIL;
Process.EnableAborts[@him.rcvr.newInput];
Process.DisableTimeout[@him.rcvr.newInput];
him.rexmtr.list ← [0, NIL];
him.rexmtr.ceiling ← System.MicrosecondsToPulses[
LONG[TcpStreamInternal.rexmtrDefaults.ceiling]*LONG[1000]];
him.rexmtr.floor ← System.MicrosecondsToPulses[
LONG[TcpStreamInternal.rexmtrDefaults.floor]*LONG[1000]];
him.rexmtr.giveUp ← TcpStreamInternal.rexmtrDefaults.giveUp;
him.rexmtr.count ← 0; him.rexmtr.delay ← 0;
him.rexmtr.interval ← System.MicrosecondsToPulses[
IF delayToRemote = 0 THEN
LONG[TcpStreamInternal.rexmtrDefaults.initialLocal] * 1000
ELSE LONG[TcpStreamInternal.rexmtrDefaults.initialRemote] * 1000];
him.rexmtr.calculationInterval ← System.MicrosecondsToPulses[
LONG[TcpStreamInternal.rexmtrDefaults.calculationInterval] * 1000];
him.rexmtr.calculation ← time;
him.rexmtr.process ← NIL;
Process.EnableAborts[@him.rexmtr.condition];
Process.SetTimeout[
@him.rexmtr.condition, CommUtil.PulsesToTicks[[him.rexmtr.floor/2]]];
--set for real when syn comes in.
him.xmtr.iss ← him.xmtr.maxSeq ← him.xmtr.unackedSeq ← him.xmtr.nextSeq ← 0;
him.xmtr.maxAlloc ← TcpStreamInternal.xmtrAlloc;
him.xmtr.blocked ← [NIL, 0];
him.xmtr.clientProcess ← NIL;
him.xmtr.timeWaitStart ← 0;
him.xmtr.context ← NIL;
Process.DisableTimeout[@him.xmtr.newAllocation];
Process.EnableAborts[@him.xmtr.newAllocation];
him.connection.state ← closed;
him.connection.stateBeforeSuspension ← closed;
him.connection.whySuspended ← notSuspended;
him.connection.offNet ← FALSE;
him.connection.pleaseStop ← FALSE;
--may be changed by max size option exchange.
him.rcvr.maxTcpBytes ← him.xmtr.maxTcpBytes ←
TcpStreamInternal.maxTcpDataBytes;
Process.SetTimeout[@him.connection.isEstablished, Process.MsecToTicks[2000]];
Process.EnableAborts[@him.connection.isEstablished];
him.connection.port ← TcpPort.CreateTcpPort[port: localPort,
send: TcpStreamInternal.send, receive: TcpStreamInternal.receive,
remote: remote, remotePort: remotePort];
him.connection.localAddr ← ArpaPort.GetAssignedAddress[him.connection.port];
him.connection.remoteAddr ← remote;
IF delayToRemote # 0 THEN him.connection.offNet ← TRUE ELSE him.connection.offNet ← FALSE;
him.connection.localPort ← localPort;
him.connection.remotePort ← remotePort;
him.connection.timeout ← timeout;
him.connection.precedence ← precedence;
him.connection.security ← security;
--options are ignored right now, since the only actual option is max size,
--set by us (not the client), in the connection request only.
him.connection.options ← options;
ArpaPort.SetWaitTime[him.connection.port, LAST[ArpaPort.WaitTime]];
him.connection.pool ← ArpaPort.GetBufferPool[him.connection.port];
him.connection.family ← Protocol1.GetFamilyUnit[arpa]; --pointer to family
END; --InitStream
GetDataLength: PUBLIC PROC [body: ArpaBuffer.Body]
RETURNS [l: CARDINAL, p: LONG POINTER] =
--returns the data length in bytes and a pointer to the data in the buffer.
BEGIN
p ← @body.ipData + (body.tcp.dataOffset * 2);
l ← (body.ipHeader.ihl * 4) + (body.tcp.dataOffset * 4); --headers length
--we don't want l going negative if remote screwed up.
IF l > body.ipHeader.length THEN l ← 0 ELSE l ← body.ipHeader.length - l;
END; --GetDataLength
PrecedenceMatch: PUBLIC PROC [body: ArpaBuffer.Body] RETURNS [BOOLEAN] =
BEGIN
RETURN[TRUE];
END; --PrecedenceMatch
SecurityMatch: PUBLIC PROC [body: ArpaBuffer.Body] RETURNS [BOOLEAN] =
BEGIN
RETURN[TRUE];
END; --SecurityMatch
SetHeaderFields: PUBLIC PROC[
b: ArpaBuffer.Buffer, dataLen, optionsLen: CARDINAL] =
BEGIN
<<
PROCESS: RECEIVER, CLIENT SENDER
Sets the header fields (IP and TCP) of the packet.
>>
headerBytes: CARDINAL; --for setting length, .. tcp header may be padded
ipOptionsSize: CARDINAL ← 0;
body: ArpaBuffer.Body = b.arpa;
him: LONG POINTER TO FRAME[TcpImpl] = LOOPHOLE[Runtime.GetCaller[]];
b.fo.time ← System.GetClockPulses[]; --record packet send time
b.fo.tries ← 1; --number of times we transmitted this packet.
body.ipHeader.protocol ← tcp;
body.ipHeader.destination ← him.connection.remoteAddr;
body.ipHeader.service ← TcpStreamInternal.tos;
body.ipHeader.identification ← UniquePktID[]; --for frag/reassembly.
body.ipHeader.lifetime ← TcpStreamInternal.ttl;
body.ipHeader.flags.dontFragment ← ~TcpStreamInternal.fragAllowed;
IF him.connection.security # NIL THEN
BEGIN
securityPtr: TcpStream.Security ← LOOPHOLE[@body.ipHeader.options];
securityPtr↑ ← him.connection.security↑;
ipOptionsSize ← SIZE[TcpStream.Security] * bpw;
END;
body.tcp.reserved ← 0;
headerBytes ← optionsLen + TcpStreamInternal.minTcpHeaderBytes;
body.tcp.dataOffset ← (headerBytes + 3) / 4;
body.tcp.destinationPort ← him.connection.remotePort;
--we set lengths here because we needed all the other header info first.
ArpaPort.SetIPLengths[body, ipOptionsSize, headerBytes + dataLen];
--checksum is set when the packet is sent.
END; --SetHeaderFields
UniquePktID: PUBLIC ENTRY PROC RETURNS [WORD] =
{RETURN[(seed ← SUCC[seed])]};
END..
LOG
3-Oct-85 9:48:32 SMA Created file - stateless procs from TcpImpl.
30-Jan-86 11:57:03 SMA GetDataLen returns length and pointer to data.
18-Jul-86 11:37:36 AOF 32-bit math procs use 'INT' rather than 'INTEGER'.
2-Feb-87 11:36:35 SMA Moved stuff from TcpImpl to shut up compiler.
5-Feb-87 10:49:50 SMA xmtr.blocked for allocation probing.
11-Mar-87 10:00:46 AOF Funston buffer management.
11-Mar-87 10:04:28 AOF made UniquePktID a random seed, montonic↑ function.
11-Mar-87 10:18:05 AOF Made low-level functions INLINEs in interface.
2-Jun-87 10:58:40 AOF Caching of DataObject entries.