-- File: NewNetworkStreamImpl.mesa - last edit: -- MXI 27-Oct-87 15:04:05 -- Copyright (C) 1984, 1985, 1986, 1987 by Xerox Corporation. All rights reserved. DIRECTORY Buffer USING [], BufferOps USING [GetSizes], CommSwitches USING [xmtRateControl, xmtRateT1, xmtRate64], CommFlags USING [doDebug], CommUtil USING [PulsesToTicks], Driver USING [Device, Glitch, nilDevice], Environment USING [bytesPerWord, nullBlock], HostNumbers USING [IsMulticastID], Inline USING [BITAND, LongCOPY], NetworkStream USING [ConnectionFailed, ConnectionID, CreateTransducer, defaultWaitTime, infiniteWaitTime, ListenError, WaitTime], NetworkStreamInternal USING [ListenerHandle], NetworkStreamImpl USING [attn, connection, packetStreamObject, probe, rcvr, rexmtr, startByteStream, stopByteStream, xmtr], NewNetworkStream USING [NegotiationParameters, nullTypeValuePairs, TSap, TSapObject, TypeValuePairs], NSBuffer USING [Body, Buffer, Dequeue, GetBuffer, ReturnBuffer], NSTypes USING [bytesPerIDPHeader, bytesPerSppHeader, ConnectionID, maxDataBytesPerSpp, maxIDPBytesPerPacket, WaitTime], PacketStream USING [bytesPerSequencedPktHeader, ConnectionAlreadyThere, ConnectionFailed, Handle, unknownConnID], Protocol1 USING [Family, GetFamilyUnit, SetMaximumBufferSize], Process USING [DisableTimeout, EnableAborts, SetTimeout], Router USING [GetDelayToNet, NoTableEntryForNet], RouterInternal USING [SendErrorPacket], Runtime USING [GetCaller], SpecialSystem USING [HostNumber], SppNegotiation USING [NegotiationHints, NewMake], SppOps USING [DisableChecksums, DisableProbes, EnableChecksums, EnableProbes, GlobalFrameFromByteStream, GlobalFrameFromPacketStream, nullAttention, PacketStreamFromByteStream, sppWindowSize], Socket USING [ChannelHandle, Create, GetBufferPool, GetAssignedAddress, GetPacket, PutPacket, SetWaitTime, TimeOut], Stream USING [Handle], System USING [GetClockPulses, MicrosecondsToPulses, NetworkAddress, NetworkNumber, nullNetworkAddress, switches]; NewNetworkStreamImpl: MONITOR IMPORTS BufferOps, CommUtil, Driver, HostNumbers, Inline, NetworkStream, NSBuffer, PacketStream, Protocol1, Process, Router, RouterInternal, Runtime, SppNegotiation, SppOps, Socket, System EXPORTS Buffer, NetworkStream, NewNetworkStream, SppNegotiation, System = BEGIN --EXPORTED TYPE(S) and READONLY Variables HostNumber: PUBLIC <<System>> TYPE = SpecialSystem.HostNumber; ListenerHandle: PUBLIC <<NetworkStream>> TYPE = NetworkStreamInternal.ListenerHandle; ConnectionID: PUBLIC <<NetworkStream>> TYPE = NSTypes.ConnectionID; Device: PUBLIC <<Buffer>> TYPE = Driver.Device; -- Types NegotiationParameters: TYPE = NewNetworkStream.NegotiationParameters; TSap: TYPE = NewNetworkStream.TSap; TSapObject: TYPE = NewNetworkStream.TSapObject; -- Internal variables unknownCID, uniqueCID: ConnectionID = PacketStream.unknownConnID; maxAlloc: CARDINAL ← SppOps.sppWindowSize; uniqueTSapObject: TSapObject = [ address: System.nullNetworkAddress, connectionID: uniqueCID]; bytesPerHeader: CARDINAL = NSTypes.bytesPerIDPHeader + NSTypes.bytesPerSppHeader; maxSppBytesWithMaxBuffer: CARDINAL ← BufferOps.GetSizes[][maxBuffer] - bytesPerHeader; -- Following default value should be identical to ones in NetworkStreamImpl. xmtrDefaults: RECORD [allocation, rateControlPause, delay1Hop, delayNHopT1, delayNHop64, delayNHop96, totalQuench: CARDINAL] = [1, 50, 50, 100, 120, 300, 16]; rcvrDefaults: RECORD [accept, duplicate: INTEGER] = [2, 20]; rexmtrDefaults: RECORD [flushRoute, giveUp, <<numbers of packets>> initialLocal, initialRemote, ceiling, floor, calculationInterval: CARDINAL <<msecs>>] = [8, 30, 500, 6000, 24000, 200, 5000]; probeDefaults: RECORD [giveUp, inactiveInterval, allocInterval, hopDelay: CARDINAL] = [8, 5000, 2000, 2000]; streamParms: RECORD [send, receive, xmtrAlloc, rcvrAlloc: CARDINAL] = [3, 4, 0, 0]; maxMsecToPulses: LONG CARDINAL = LAST[LONG CARDINAL] / 1000; -- Internal errors BadDestintationAddress: ERROR = CODE; --for glitching -- Public procedures NewApprove: PUBLIC PROC[listenerH: ListenerHandle, negotiationParameters: NegotiationParameters ← NIL, streamTimeout: NetworkStream.WaitTime ← NetworkStream.infiniteWaitTime] RETURNS [sH: Stream.Handle] = BEGIN localTSapObject: TSapObject ← uniqueTSapObject; remoteTSapObject: TSapObject ← [ listenerH.buffer.ns.source, listenerH.buffer.ns.sourceConnectionID]; IF (listenerH = NIL) OR (listenerH.seal # listenerSeal) THEN ERROR NetworkStream.ListenError[illegalHandle]; IF listenerH.state # pending THEN ERROR NetworkStream.ListenError[illegalState]; IF GetNegBit[listenerH.buffer.ns] THEN sH ← NewTransducer[ @localTSapObject, @remoteTSapObject, NIL, [TRUE, listenerH.buffer.fo.driver.device], streamTimeout! UNWIND => { NSBuffer.ReturnBuffer[listenerH.buffer]; listenerH.state ← idle}] ELSE sH ← NetworkStream.CreateTransducer[ localTSapObject.address, listenerH.buffer.ns.source, Environment.nullBlock, unknownCID, listenerH.buffer.ns.sourceConnectionID, TRUE, streamTimeout, bulk ! UNWIND => { NSBuffer.ReturnBuffer[listenerH.buffer]; listenerH.state ← idle}]; NSBuffer.ReturnBuffer[listenerH.buffer]; listenerH.state ← idle; END; NewCreate: PUBLIC PROC[ remote: System.NetworkAddress, negotiationParameters: NegotiationParameters ← NIL, timeout: NetworkStream.WaitTime ← NetworkStream.defaultWaitTime] RETURNS [Stream.Handle] = BEGIN localTSapObject: TSapObject ← uniqueTSapObject; remoteTSapObject: TSapObject ← [remote, uniqueCID]; RETURN[ NewTransducer[ @localTSapObject, @remoteTSapObject, NIL, [TRUE, ethernet], timeout]]; END; --Create NewTransducer: PUBLIC PROC[ local, remote: TSap, --for the connection to be created negotiationParameters: NegotiationParameters ← NIL, hints: SppNegotiation.NegotiationHints, timeout: NetworkStream.WaitTime ← NetworkStream.defaultWaitTime] RETURNS [sH: Stream.Handle] = BEGIN psH: PacketStream.Handle; instanceN: LONG POINTER TO FRAME[NetworkStreamImpl]; SELECT TRUE FROM (~HostNumbers.IsMulticastID[@remote.address.host]) => NULL; --okay (~CommFlags.doDebug) => --DON'T LET HIM GET AWAY WITH THIS-- DO SIGNAL NetworkStream.ConnectionFailed[noTranslationForDestination]; ENDLOOP; ENDCASE => Driver.Glitch[BadDestintationAddress]; psH ← SppNegotiation.NewMake[ local, remote, negotiationParameters, hints, timeout]; instanceN ← SppOps.GlobalFrameFromPacketStream[psH]; sH ← instanceN.startByteStream[psH]; sH.delete ← Delete; --don't use instance's version of delete END; --CreateTransducer NewListen: PUBLIC PROC[ listenerH: ListenerHandle, listenTimeout: NetworkStream.WaitTime ← NetworkStream.infiniteWaitTime] RETURNS [remote: System.NetworkAddress] = BEGIN GetPacket: ENTRY PROC = BEGIN ENABLE UNWIND => NULL; WHILE (b ← NSBuffer.Dequeue[@listenerH.queue]) = NIL DO WAIT listenerH.condition; ENDLOOP; END; --GetPacket b: NSBuffer.Buffer; IF (listenerH = NIL) OR (listenerH.seal # listenerSeal) THEN ERROR NetworkStream.ListenError[illegalHandle]; b ← listenerH.buffer; SELECT listenerH.state FROM pending => RouterInternal.SendErrorPacket[b, listenerReject]; listening => ERROR NetworkStream.ListenError[illegalState]; ENDCASE; listenerH.state ← listening; Socket.SetWaitTime[listenerH.socket, listenTimeout]; DO --until the packet is a sequenced packet and is not a duplicate, --or timeout, or aborted socket body: NSBuffer.Body; GetPacket[ ! UNWIND => listenerH.state ← idle]; IF b = NIL THEN LOOP; --nothing happening here body ← b.ns; --makes for cheaper access --discard any cases with something wrong, ENDCASE is only acceptable packet SELECT TRUE FROM (b.fo.status # goodCompletion) => NSBuffer.ReturnBuffer[b]; --don't chance it with bad buffers (HostNumbers.IsMulticastID[@body.destination.host]) => NSBuffer.ReturnBuffer[b]; --he's insane, but can't error broadcast (HostNumbers.IsMulticastID[@body.source.host]) => NSBuffer.ReturnBuffer[b]; --he's busted, and I don't care (body.packetType # sequencedPacket) => RouterInternal.SendErrorPacket[b, invalidPacketType]; (body.destinationConnectionID # unknownCID) => RouterInternal.SendErrorPacket[b, protocolViolation]; (body.sourceConnectionID = unknownCID) => RouterInternal.SendErrorPacket[b, protocolViolation]; (body.sequenceNumber # 0) => RouterInternal.SendErrorPacket[b, protocolViolation]; (~body.systemPacket) => RouterInternal.SendErrorPacket[b, protocolViolation]; (~PacketStream.ConnectionAlreadyThere[ body.source, body.sourceConnectionID]) => BEGIN listenerH.buffer ← b; listenerH.state ← pending; RETURN [body.source]; END; ENDCASE => NSBuffer.ReturnBuffer[b]; ENDLOOP; END; --Listen NewReject: PUBLIC PROC[listenerH: ListenerHandle] = BEGIN IF (listenerH = NIL) OR (listenerH.seal # listenerSeal) THEN ERROR NetworkStream.ListenError[illegalHandle]; IF listenerH.state # pending THEN ERROR NetworkStream.ListenError[illegalState]; -- Should send SppError packet. But currently let them timeout... NSBuffer.ReturnBuffer[listenerH.buffer]; listenerH.state ← idle; END; InitializeInternal: PROC [hops: NATURAL, instance: LONG POINTER TO FRAME[NetworkStreamImpl]] = BEGIN time: LONG CARDINAL = System.GetClockPulses[]; instance.xmtr.clientProcess ← NIL; instance.xmtr.maxSeq ← xmtrDefaults.allocation - 1; instance.xmtr.unackedSeq ← instance.xmtr.nextSeq ← 0; instance.xmtr.maxAlloc ← streamParms.xmtrAlloc + SppOps.sppWindowSize; instance.xmtr.blocked ← instance.xmtr.checksums ← TRUE; --default & starting point instance.xmtr.transmitProc ← Socket.PutPacket; --default & starting point instance.xmtr.rateControlling ← (hops # 0) AND (System.switches[CommSwitches.xmtRateControl] = down); instance.xmtr.interval ← SELECT TRUE FROM (~instance.xmtr.rateControlling) => 0, --we're not doing this (hops = 1) => System.MicrosecondsToPulses[xmtrDefaults.delay1Hop], (System.switches[CommSwitches.xmtRateT1] = down) => System.MicrosecondsToPulses[xmtrDefaults.delayNHopT1], (System.switches[CommSwitches.xmtRate64] = down) => System.MicrosecondsToPulses[xmtrDefaults.delayNHop64], ENDCASE => System.MicrosecondsToPulses[xmtrDefaults.delayNHop96]; instance.xmtr.interval ← 1000 * instance.xmtr.interval; --we really wanted usecs instance.xmtr.quenchIncr ← 0; --we haven't started yet instance.xmtr.lastXmt ← time; --that's to start with Process.DisableTimeout[@instance.xmtr.newAllocation]; Process.EnableAborts[@instance.xmtr.newAllocation]; instance.probe.inactiveInterval ← 1000 * System.MicrosecondsToPulses[ probeDefaults.inactiveInterval + (probeDefaults.hopDelay * hops)]; instance.probe.allocInterval ← 1000 * System.MicrosecondsToPulses[ probeDefaults.allocInterval + (probeDefaults.hopDelay * hops)]; instance.probe.lastTime ← time; instance.probe.unacked ← 0; instance.probe.probing ← TRUE; instance.rexmtr.ceiling ← 1000 * System.MicrosecondsToPulses[rexmtrDefaults.ceiling]; instance.rexmtr.floor ← 1000 * System.MicrosecondsToPulses[rexmtrDefaults.floor]; instance.rexmtr.giveUp ← rexmtrDefaults.giveUp; instance.rexmtr.count ← 0; instance.rexmtr.delay ← 0; instance.rexmtr.interval ← 1000 * System.MicrosecondsToPulses[ IF hops = 0 THEN rexmtrDefaults.initialLocal ELSE rexmtrDefaults.initialRemote]; instance.rexmtr.calculationInterval ← 1000 * System.MicrosecondsToPulses[ rexmtrDefaults.calculationInterval]; instance.rexmtr.calculation ← time; instance.rexmtr.process ← NIL; Process.EnableAborts[@instance.rexmtr.condition]; Process.SetTimeout[ @instance.rexmtr.condition, CommUtil.PulsesToTicks[[instance.rexmtr.floor / 2]]]; instance.rcvr.nextSeq ← 0; instance.rcvr.blocked ← instance.rcvr.acksReqested ← FALSE; instance.rcvr.maxSeq ← instance.rcvr.maxAlloc ← streamParms.rcvrAlloc + SppOps.sppWindowSize; instance.rcvr.process ← NIL; instance.rcvr.table.slot ← ALL[NIL]; instance.rcvr.table.index ← instance.rcvr.table.length ← 0; Process.EnableAborts[@instance.rcvr.table.condition]; Process.DisableTimeout[@instance.rcvr.table.condition]; instance.rexmtr.table.index ← instance.rexmtr.table.length ← 0; instance.rexmtr.table.slot ← ALL[NIL]; Process.EnableAborts[@instance.rexmtr.table.condition]; Process.DisableTimeout[@instance.rexmtr.table.condition]; instance.attn.table.index ← instance.attn.table.length ← 0; instance.attn.table.slot ← ALL[SppOps.nullAttention]; Process.EnableAborts[@instance.attn.table.condition]; Process.DisableTimeout[@instance.attn.table.condition]; END; --InitializeInternal; InitializeSppState: PUBLIC PROC [ local, remote: System.NetworkAddress, localID, remoteID: ConnectionID, timeout: NSTypes.WaitTime] = BEGIN hops: NATURAL; instance: LONG POINTER TO FRAME[NetworkStreamImpl] ← LOOPHOLE[Runtime.GetCaller[]]; socket: Socket.ChannelHandle; hops ← Router.GetDelayToNet[remote.net! Router.NoTableEntryForNet => {hops ← 0; CONTINUE}]; InitializeInternal[hops, instance]; socket ← Socket.Create[ socket: local.socket, type: sequencedPacket, send: 16, receive: 17]; Socket.SetWaitTime[socket, LAST[NSTypes.WaitTime]]; --no timeouts here instance.connection ← [ state: IF remoteID = unknownCID THEN unestablished ELSE established, stateBeforeSuspension: unestablished, whySuspended: notSuspended, maxSppBytes: NSTypes.maxDataBytesPerSpp, timeout: timeout, hops: hops, socket: socket, remoteAddr: remote, remoteID: remoteID, localAddr: Socket.GetAssignedAddress[socket], localID: localID, pool: Socket.GetBufferPool[socket], whyFailed: timeout]; END; --InitializeSppState; << TABLE: Four case of establishment (local address/id is valid) startProc remoteAddr/Id actEst state NewCreate no (socket)/no TRUE idle -(TX)-> passiveNegotiation NewApprove valid/valid TRUE activeNegotiation -(TX)-> waitForDecision NewTransducer valid/no TRUE idle -(TX)-> passiveNegotiation NewTransducer valid/no FALSE idle >> NegTypes: TYPE = MACHINE DEPENDENT { size(1), -- (packets) -- The size of the data portion of the SPP data unit. window(2), -- (packets) -- The number of packets to be advertised in the allocation window. xmti(3), -- (millisecs) The minimum interpacket transmit interval. rxmtf(4), -- (millisecs) The minimum value of the retransmission interval -- that is calculated based on stream history. rxmtc(5), -- (millisecs) The maximum value of the retransmission interval -- that is calculated based on stream history. rxmtl(6), -- (packets) The number of times a data packet should be retransmitted -- at the current retransmit interval before the connection is abandoned. check(7), -- (switch) Should the connection generate/check software checksums? probe(8) -- (switch) Should the connection generate idle line probes? }; NegState: TYPE = {idle, passiveNegotiation, activeNegotiation, negotiating, waitForDecision}; NewInitializeSppState: PUBLIC PROC [ local, remote: TSap, negotiationParameters: NegotiationParameters, hints: SppNegotiation.NegotiationHints, timeout: NSTypes.WaitTime] = BEGIN hops: NATURAL; instance: LONG POINTER TO FRAME[NetworkStreamImpl] ← LOOPHOLE[Runtime.GetCaller[]]; socket: Socket.ChannelHandle; localParams: ARRAY [0..NegTypes.LAST.ORD - NegTypes.FIRST.ORD] OF NewNetworkStream.TypeValuePairs ← ALL[NewNetworkStream.nullTypeValuePairs]; CollectNegotiationParams: PROC = BEGIN index: CARDINAL ← 0; IF negotiationParameters = NIL THEN BEGIN negotiationParameters ← DESCRIPTOR[localParams]; FOR n: NegTypes IN NegTypes DO negotiationParameters[index].type ← n.ORD; index ← index + 1; ENDLOOP; FOR index IN [0..negotiationParameters.LENGTH) DO SELECT localParams[index].type FROM NegTypes.size.ORD => localParams[index].value ← [value[ IF hops = 0 THEN maxSppBytesWithMaxBuffer ELSE instance.connection.maxSppBytes]]; NegTypes.window.ORD => localParams[index].value ← [value[ MAX [instance.xmtr.maxAlloc, MIN [hops * 2, 13]]]]; NegTypes.xmti.ORD => localParams[index].value ← [value[CARDINAL[ instance.xmtr.interval / 1000]]]; -- usec to msec NegTypes.rxmtf.ORD => localParams[index].value ← [value[CARDINAL[ instance.rexmtr.floor / 1000]]]; -- usec to msec NegTypes.rxmtc.ORD => localParams[index].value ← [value[CARDINAL[ instance.rexmtr.ceiling / 1000]]]; -- usec to msec NegTypes.rxmtl.ORD => localParams[index].value ← [value[CARDINAL[ instance.rexmtr.interval / 1000]]]; -- usec to msec NegTypes.check.ORD => localParams[index].value ← [switch[ IF hops = 0 AND hints.driver = ethernet THEN off ELSE on]]; NegTypes.probe.ORD => localParams[index].value ← [switch[on]]; ENDCASE; ENDLOOP; END ELSE BEGIN -- Copy client's data valid: CARDINAL ← 0; FOR index IN [0..negotiationParameters.LENGTH) DO IF negotiationParameters[index].type IN [NegTypes.FIRST.ORD..NegTypes.LAST.ORD] THEN BEGIN localParams[index] ← negotiationParameters[index]; valid ← valid + 1; END; ENDLOOP; negotiationParameters ← DESCRIPTOR[@localParams, valid]; END; END; ApplyNegotiationParams: PROC = BEGIN FOR index: CARDINAL IN [0..negotiationParameters.LENGTH) DO SELECT localParams[index].type FROM NegTypes.size.ORD => instance.connection.maxSppBytes ← localParams[index].value.v; NegTypes.window.ORD => instance.xmtr.maxAlloc ← localParams[index].value.v; NegTypes.xmti.ORD => instance.xmtr.interval ← LONG[localParams[index].value.v]; NegTypes.rxmtf.ORD => instance.rexmtr.floor ← LONG[localParams[index].value.v]; NegTypes.rxmtc.ORD => instance.rexmtr.ceiling ← LONG[localParams[index].value.v]; NegTypes.rxmtl.ORD => instance.rexmtr.interval ← LONG[localParams[index].value.v]; NegTypes.check.ORD => SELECT localParams[index].value.s FROM on => SppOps.EnableChecksums[@instance.packetStreamObject]; off => SppOps.DisableChecksums[@instance.packetStreamObject]; ENDCASE; NegTypes.probe.ORD => SELECT localParams[index].value.s FROM on => SppOps.EnableProbes[@instance.packetStreamObject]; off => SppOps.DisableProbes[@instance.packetStreamObject]; ENDCASE; ENDCASE; ENDLOOP; END; systemPacketSize: CARDINAL = PacketStream.bytesPerSequencedPktHeader; bytesPerTypeValuePairs: CARDINAL = SIZE[NewNetworkStream.TypeValuePairs] * Environment.bytesPerWord; previousType: [0..17B); SendPacket: PROC [type: [0..17B)] = BEGIN buffer: NSBuffer.Buffer ← NIL; body: NSBuffer.Body ← NIL; paramsBytes: CARDINAL ← 0; IF type = paramType THEN paramsBytes ← negotiationParameters.LENGTH * bytesPerTypeValuePairs; buffer ← NSBuffer.GetBuffer[aH: instance.connection.pool, wait: TRUE, function: send, size: systemPacketSize + paramsBytes]; body ← buffer.ns; body.pktLength ← systemPacketSize + paramsBytes; body.packetType ← sequencedPacket; body.destination ← instance.connection.remoteAddr; body.systemPacket ← body.sendAck ← TRUE; body.attention ← body.endOfMessage ← FALSE; body.unusedType ← type; body.subtype ← 0; body.sourceConnectionID ← instance.connection.localID; body.destinationConnectionID ← instance.connection.remoteID; body.sequenceNumber ← 0; body.acknowledgeNumber ← 0; body.allocationNumber ← maxAlloc; IF paramsBytes # 0 THEN Inline.LongCOPY[from: @localParams, nwords: paramsBytes / Environment.bytesPerWord, to: @body.sppWords]; Socket.PutPacket[instance.connection.socket, buffer]; previousType ← type; END; CheckParameters: PROC [body: NSBuffer.Body] RETURNS [BOOLEAN] = BEGIN remoteParams: NegotiationParameters ← DESCRIPTOR[ @body.sppWords, (body.pktLength - systemPacketSize) / bytesPerTypeValuePairs]; -- Do checking -- 'negotiationParameters' will points local parameters -- 'remoteParams' will points local parameters -- negotiated result should be stored in negotiationParameters -- Apply params will use negotiationParameters -- New proposition also have to be stored in local parameters RETURN[TRUE]; -- For now END; -- When this procedure is called, -- negotiated parameter should be stored in localParams SetMaxBufferSize: PROC = BEGIN maxSize: CARDINAL ← NSTypes.maxIDPBytesPerPacket; family: Protocol1.Family; -- Get negotiated max buffer size FOR i: CARDINAL IN [0..negotiationParameters.LENGTH) DO IF negotiationParameters[i].type # NegTypes.size.ORD THEN LOOP; maxSize ← bytesPerHeader + negotiationParameters[i].value.v; EXIT ENDLOOP; family ← Protocol1.GetFamilyUnit[ns]; IF family.maxBufferSize < maxSize THEN Protocol1.SetMaximumBufferSize[Driver.nilDevice, family, maxSize]; END; Negotiate: PROC RETURNS [succeed: BOOLEAN ← FALSE] = BEGIN state: NegState ← idle; buffer: NSBuffer.Buffer ← NIL; body: NSBuffer.Body ← NIL; continue: BOOLEAN ← TRUE; time, interval: LONG CARDINAL; -- Initial action SELECT TRUE FROM remote.connectionID # LOOPHOLE[unknownCID] => BEGIN -- NewApprove case SendPacket[paramType]; state ← waitForDecision; END; hints.activeEstablish => BEGIN -- NewCreate or NewTransducer (active side) send RFC SendPacket[negType]; state ← passiveNegotiation; END; ENDCASE => BEGIN -- NewTransducer (passive side) wait RFC state ← idle; END; -- Set timeout interval timeout ← MAX[4000, timeout]; -- Argument timeout could be updated here. interval ← IF timeout > maxMsecToPulses THEN LAST[LONG CARDINAL] ELSE System.MicrosecondsToPulses[timeout*1000]; time ← System.GetClockPulses[]; Socket.SetWaitTime[socket, 2000]; -- Wait for response WHILE continue DO buffer ← NIL; buffer ← Socket.GetPacket[ instance.connection.socket!Socket.TimeOut => CONTINUE]; IF buffer = NIL THEN IF System.GetClockPulses[] - time > interval THEN << Timeout >> SIGNAL PacketStream.ConnectionFailed[timeout] ELSE << Retry >> BEGIN SendPacket[previousType]; LOOP; END; time ← System.GetClockPulses[]; body ← buffer.ns; IF body.packetType = sequencedPacket AND body.systemPacket THEN SELECT state FROM idle => IF body.source = instance.connection.remoteAddr THEN BEGIN instance.connection.remoteID ← body.sourceConnectionID; IF GetNegBit[body] THEN SendPacket[paramType] -- Send parameter ELSE continue ← FALSE; -- Remote doesn't understand negotiation. Failed... END; passiveNegotiation => IF body.source.host = instance.connection.remoteAddr.host THEN BEGIN instance.connection.remoteAddr.socket ← body.source.socket; instance.connection.remoteID ← body.sourceConnectionID; IF GetParamBit[body] THEN -- If parameter is acceptable then end negotiation IF CheckParameters[body] THEN BEGIN continue ← FALSE; succeed ← TRUE; --Yeah!! SetMaxBufferSize[]; END -- If parameter is noy acceptable then continue -- Propose defferenct parameters ELSE SendPacket[paramType] ELSE continue ← FALSE; -- Remote doesn't understand negotiation. Failed... END; waitForDecision => BEGIN IF GetParamBit[body] THEN -- Remote didn't agree to the parameters. They sent their proposition. IF CheckParameters[body] THEN BEGIN -- We agree to their proposition continue ← FALSE; succeed ← TRUE; --Yeah!! SetMaxBufferSize[]; END -- We don't agree to their proposition. Send our new proposition. ELSE SendPacket[paramType] ELSE BEGIN -- Remote agreed to the parameters continue ← FALSE; succeed ← TRUE; --Yeah!! SetMaxBufferSize[]; END; END; ENDCASE; NSBuffer.ReturnBuffer[buffer]; ENDLOOP; IF remote.connectionID # LOOPHOLE[unknownCID] THEN instance.connection.state ← established; Socket.SetWaitTime[socket, LAST[NSTypes.WaitTime]]; --no timeouts here END; hops ← Router.GetDelayToNet[remote.address.net! Router.NoTableEntryForNet => {hops ← 0; CONTINUE}]; InitializeInternal[hops, instance]; socket ← Socket.Create[ socket: local.address.socket, type: sequencedPacket, send: 16, receive: 17]; Socket.SetWaitTime[socket, LAST[NSTypes.WaitTime]]; --no timeouts here instance.connection ← [ state: unestablished, stateBeforeSuspension: unestablished, whySuspended: notSuspended, maxSppBytes: NSTypes.maxDataBytesPerSpp, timeout: timeout, hops: hops, socket: socket, remoteAddr: remote.address, remoteID: remote.connectionID, localAddr: Socket.GetAssignedAddress[socket], localID: local.connectionID, pool: Socket.GetBufferPool[socket], whyFailed: timeout]; CollectNegotiationParams[]; IF Negotiate[] THEN ApplyNegotiationParams[]; END; --NewInitializeSppState; -- Internal procedures -- Assignment -- 0: systemPacket -- 1: sendAck -- 2: attention -- 3: endOfMessage -- 4: negotiation -- 5: parameter negMask: UNSPECIFIED = 0008H; paramMask: UNSPECIFIED = 0004H; negType: [0..17B) = 8H; paramType: [0..17B) = 4H; nullType: [0..17B) = 0H; GetNegBit: PROCEDURE [b: NSBuffer.Body] RETURNS [BOOLEAN] = INLINE BEGIN RETURN[Inline.BITAND[negMask, b.unusedType]]; END; GetParamBit: PROCEDURE [b: NSBuffer.Body] RETURNS [BOOLEAN] = INLINE BEGIN RETURN[Inline.BITAND[paramMask, b.unusedType]]; END; Delete: PROC[sH: Stream.Handle] = BEGIN --delete instance associcated with this stream instanceN: LONG POINTER TO FRAME[NetworkStreamImpl] = SppOps.GlobalFrameFromByteStream[sH]; psH: PacketStream.Handle = SppOps.PacketStreamFromByteStream[sH]; instanceN.stopByteStream[]; --shut down the bytestream psH.destroy[psH]; --then the underlying packet stream END; END. -- NewNetworkStreamImpl LOG 27-Oct-87 15:05:06 MXI Created for SPP negotiation.