-- 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.