DIRECTORY Basics USING [BITNOT], BasicTime USING [GMT, Now, Period], Convert USING [RopeFromTime, TimeFromRope], PrincOps USING [zEXCH], UDP USING [BodyRec, default, date, echo, Handle, HandleRec, maxLength, minLength, Port, PseudoHeader, time], IO USING [STREAM], IPConfig USING [ourLocalAddress], IPDefs USING [Byte, CreateIPHandle, DataBuffer, Datagram, DByte, UDPProtocol, Address, InternetHandle, InternetHeader, nullAddress, PrintDatagram, Receive, RequestData, SendSpecific], IPOps USING [maxTTL, OnesComplementAddBlock], Process USING [Detach, DisableTimeout, MsecToTicks, SetTimeout], Rope USING [Fetch, Length, ROPE]; UDPImpl: CEDAR MONITOR IMPORTS Basics, BasicTime, Convert, IPConfig, IPDefs, IPOps, Process, Rope EXPORTS UDP = BEGIN logStream: IO.STREAM _ NIL; nextPort: UDP.Port _ 256; users: LIST OF InfoRef _ NIL; InfoRef: TYPE = REF InfoRec; InfoRec: TYPE = RECORD [ handle: UDP.Handle, port: UDP.Port, waiting: CONDITION, queue: LIST OF IPDefs.Datagram]; RequestedPortAlreadyInUse: ERROR = CODE; Create: PUBLIC ENTRY PROC [him: IPDefs.Address, remote: UDP.Port, local: UDP.Port _ UDP.default] RETURNS [handle: UDP.Handle] = { new: InfoRef; IF local = UDP.default THEN local _ (nextPort _ nextPort.SUCC); handle _ NEW[UDP.HandleRec _ [local: local, remote: remote, him: him]]; new _ NEW[InfoRec _ [handle: handle, port: local, waiting: , queue: NIL]]; IF users = NIL THEN { users _ CONS[new, NIL]; RETURN; }; FOR user: LIST OF InfoRef _ users, user.rest DO this: InfoRef _ user.first; IF this.port = local THEN ERROR RequestedPortAlreadyInUse; IF user.rest = NIL THEN {user.rest _ CONS[new, NIL]; RETURN; }; ENDLOOP; }; Destroy: PUBLIC ENTRY PROC [handle: UDP.Handle] = { IF users = NIL THEN ERROR; IF users.first.handle = handle THEN {users _ users.rest; RETURN; }; FOR user: LIST OF InfoRef _ users, user.rest DO IF users.rest = NIL THEN ERROR; IF user.rest.first.handle = handle THEN {user.rest _ user.rest.rest; RETURN; }; ENDLOOP; }; Receive: PUBLIC ENTRY PROC [handle: UDP.Handle, timeout: INT] RETURNS [data: IPDefs.Datagram] = TRUSTED { FOR user: LIST OF InfoRef _ users, user.rest UNTIL user = NIL DO this: InfoRef _ user.first; IF this.handle # handle THEN LOOP; UNTIL this.queue # NIL DO IF timeout = 0 THEN Process.DisableTimeout[@this.waiting] ELSE Process.SetTimeout[@this.waiting, Process.MsecToTicks[timeout]]; WAIT this.waiting; IF timeout # 0 AND this.queue = NIL THEN RETURN[NIL]; ENDLOOP; data _ this.queue.first; this.queue _ this.queue.rest; RETURN; REPEAT FINISHED => ERROR; ENDLOOP; }; Send: PUBLIC PROC [handle: UDP.Handle, data: IPDefs.Datagram, length: INT] = TRUSTED { udp: LONG POINTER TO UDP.BodyRec _ LOOPHOLE[@data.data]; IF length < UDP.minLength THEN ERROR; IF length > UDP.maxLength THEN ERROR; data.dataLength _ length; data.inHdr.precedence _ 0; data.inHdr.delay _ 0; data.inHdr.throughput _ 0; data.inHdr.reliability _ 0; data.inHdr.dontFragment _ FALSE; data.inHdr.timeToLive _ IPOps.maxTTL; data.inHdr.protocol _ IPDefs.UDPProtocol; data.inHdr.source _ IPConfig.ourLocalAddress; data.inHdr.destination _ handle.him; udp.source _ handle.local; udp.dest _ handle.remote; udp.length _ length; udp.checksum _ Checksum[data]; IPDefs.SendSpecific[data]; }; SendReply: PUBLIC PROC [data: IPDefs.Datagram] = TRUSTED { udp: LONG POINTER TO UDP.BodyRec _ LOOPHOLE[@data.data]; tempAddress: IPDefs.Address; tempPort: UDP.Port; tempAddress _ data.inHdr.source; data.inHdr.source _ data.inHdr.destination; data.inHdr.destination _ tempAddress; tempPort _ udp.source; udp.source _ udp.dest; udp.dest _ tempPort; udp.checksum _ Checksum[data]; IPDefs.SendSpecific[data]; }; Listener: PROC = { myHandle: IPDefs.InternetHandle _ IPDefs.CreateIPHandle[ IPDefs.RequestData[ matchProtocol: TRUE, protocol: IPDefs.UDPProtocol, matchAddr: FALSE, address: IPDefs.nullAddress, matchLocalAddr: TRUE, localAddress: IPDefs.nullAddress]]; DO data: IPDefs.Datagram _ NIL; data _ myHandle.Receive[]; IF data # NIL AND IsValid[data] THEN TRUSTED { udp: LONG POINTER TO UDP.BodyRec _ LOOPHOLE[@data.data]; IF logStream # NIL THEN IPDefs.PrintDatagram[logStream, data]; IF ~TakeThisOne[data, udp.dest] THEN CheckForDefaults[data, udp.dest]; }; ENDLOOP; }; IsValid: PROC [data: IPDefs.Datagram] RETURNS [ok: BOOL] = TRUSTED BEGIN udp: LONG POINTER TO UDP.BodyRec _ LOOPHOLE[@data.data]; IF data.dataLength < UDP.minLength THEN RETURN[FALSE]; IF udp.checksum = 0 THEN RETURN[TRUE]; -- Don't care IF udp.checksum # Checksum[data] THEN RETURN[FALSE]; RETURN[TRUE]; END; Checksum: PUBLIC UNSAFE PROC [data: IPDefs.Datagram] RETURNS [checksum: IPDefs.DByte] = UNCHECKED BEGIN pseudoHeader: UDP.PseudoHeader; udp: LONG POINTER TO UDP.BodyRec _ LOOPHOLE[@data.data]; cs: CARDINAL _ Basics.BITNOT[udp.checksum]; pseudoHeader.source _ data.inHdr.source; pseudoHeader.dest _ data.inHdr.destination; pseudoHeader.zero _ 0; pseudoHeader.protocol _ data.inHdr.protocol; pseudoHeader.udpTotalBytes _ data.dataLength; IF data.dataLength MOD 2 # 0 THEN data.data[data.dataLength] _ 0; cs _ IPOps.OnesComplementAddBlock[ptr: @pseudoHeader, count: UDP.PseudoHeader.SIZE, initialSum: cs]; cs _ IPOps.OnesComplementAddBlock[ptr: udp, count: (data.dataLength+1)/2, initialSum: cs]; RETURN [Basics.BITNOT[cs]]; END; TakeThisOne: ENTRY PROC [data: IPDefs.Datagram, port: UDP.Port] RETURNS [yes: BOOL] = { ENABLE UNWIND => NULL; FOR user: LIST OF InfoRef _ users, user.rest UNTIL user = NIL DO this: InfoRef _ user.first; IF this.port # port THEN LOOP; IF this.queue = NIL THEN this.queue _ CONS[data, NIL] ELSE FOR finger: LIST OF IPDefs.Datagram _ this.queue, finger.rest DO IF finger.rest # NIL THEN LOOP; finger.rest _ CONS[data, NIL]; EXIT; ENDLOOP; NOTIFY this.waiting; RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; }; CheckForDefaults: PROC [data: IPDefs.Datagram, port: UDP.Port] = { SELECT port FROM UDP.echo => SendReply[data]; UDP.date => TRUSTED { udp: LONG POINTER TO UDP.BodyRec _ LOOPHOLE[@data.data]; date: Rope.ROPE _ Convert.RopeFromTime[BasicTime.Now[], years, seconds, TRUE]; bytes: CARDINAL _ Rope.Length[date]; FOR i: CARDINAL IN [0..bytes) DO udp.data[UDP.minLength+i] _ LOOPHOLE[Rope.Fetch[date, i]]; ENDLOOP; data.dataLength _ udp.length _ UDP.minLength+bytes; SendReply[data]; }; UDP.time => TRUSTED { udp: LONG POINTER TO UDP.BodyRec _ LOOPHOLE[@data.data]; now: BasicTime.GMT _ BasicTime.Now[]; Flop: PROC [LONG CARDINAL] RETURNS [Pair] = TRUSTED MACHINE CODE BEGIN PrincOps.zEXCH; END; Pair: TYPE = MACHINE DEPENDENT RECORD [a, b: CARDINAL]; -- used for word swap flopped: LONG POINTER TO Pair _ LOOPHOLE[@udp.data]; period: INT _ BasicTime.Period[from: baseGmt, to: now]; raw: LONG CARDINAL _ period+baseRaw; flopped^ _ Flop[raw]; data.dataLength _ udp.length _ UDP.minLength+4; SendReply[data]; }; ENDCASE => NULL; -- Drop on the floor RETURN; }; baseGmt: BasicTime.GMT _ Convert.TimeFromRope["1-Jan-70 00:00:00 GMT"]; baseRaw: LONG CARDINAL _ 2208988800; TRUSTED {Process.Detach[FORK Listener[]]}; END.  Copyright (C) 1985 by Xerox Corporation. All rights reserved. The following program was created in 1985 but has not been published within the meaning of the copyright law, is furnished under license, and may not be used, copied and/or disclosed except in accordance with the terms of said license. UDPImpl.mesa Hal Murray June 26, 1985 10:41:36 pm PDT John Larson, June 12, 1987 11:24:29 pm PDT If non-NIL (probably set from the debugger), then log incoming UDP packets. NIL if timeout (ms), 0 => Forever Reverse all the fields and send it back. Handle incoming UDP messages. Compute the header checksum for a datagram. Start with negative of the checksum that's in the header so that we don't have to smash it to zero to compute the real checksum. Find a home for this datagram and queue it. Κ – "cedar" style˜Icode2šœ©™©head™ Icode™(M™*šΟk ˜ Kšœœœ˜Kšœ œœ˜#Kšœœ˜+Jšœ œ ˜Kšœœc˜lKšœœœ˜Kšœ œ˜!Kšœœ«˜·Kšœœ"˜-Kšœœ3˜@Kšœœœ˜!——šΟnœœ˜KšœC˜JKšœœ˜ Kš˜šœ œœœ˜KšœK™K—Kšœ œ ˜šœœœ œ˜Kšœ œœ ˜šœ œœ˜Kšœœ˜Kšœœ˜Kšœ  œ˜Kšœœœ˜ ——Kšžœœœ˜(šžœœœœœœœ ˜`Kšœ œ ˜ Kšœ ˜ Kšœ œ œœ˜?Kšœ œœ7˜GKšœœ;œ˜JKš œ œœ œœœ˜8šœœœœ˜0Kšœ˜Kšœœœ˜:Kš œ œœœœœ˜?Kšœ˜ ——š žœœœœ œ ˜3Kšœ œœœ˜Kšœœœ˜Cšœœœœ˜0Kšœœœœ˜Kšœ!œœ˜OKšœ˜ ——šžœœœœ œœœœ˜iKšœ™!š œœœœœœ˜AKšœ˜Kšœœœ˜"šœœ˜Kšœ œ&˜9KšœA˜EKšœ˜Kš œ œœœœœ˜5Kšœ˜—Kšœ˜K˜Kšœ˜Kšœœœ˜Kšœ˜ ——š žœœœ œ(œœ˜VKš œœœœœ œ ˜8Kšœ œ œœ˜%Kšœ œ œœ˜%Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœœ˜ Kšœ%˜%Kšœ)˜)Kšœ-˜-Kšœ$˜$Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—šž œœœœ˜:K™(Kš œœœœœ œ ˜8Kšœ˜Kšœ œ˜Kšœ ˜ Kšœ+˜+Kšœ%˜%Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—šžœœ˜K™šœ8˜8šœ˜Kšœœ˜2Kšœ œ˜.Kšœœ%˜9——š˜Kšœœ˜Kšœ˜š œœœœœ˜.Kš œœœœœ œ ˜8Kšœ œœ'˜>Kšœœ%˜I—Kšœ˜ ——š žœœœœ˜BKš˜Kš œœœœœ œ ˜8Kš œœ œœœ˜6Kš œœœœΟc ˜5Kšœœœœ˜4Kšœœ˜ Kšœ˜—š žœœœœœ ˜aKš˜K™+Kšœœ˜Kš œœœœœ œ ˜8Kšœœ œ˜+KšŸ€™€Kšœ(˜(Kšœ+˜+K˜K˜,Kšœ-˜-Kšœœœ ˜AKšœ=œœ˜dKšœZ˜ZKšœ œ˜Kšœ˜—š ž œœœœœœ˜WK™+Kšœœœ˜š œœœœœœ˜AKšœ˜Kšœœœ˜Kš œœœœœ˜5š˜šœ œœ+œ˜AKšœœœœ˜Kšœœœ˜Kšœ˜Kšœ˜ ——Kšœ˜Kšœœ˜ Kšœ˜ —Kšœœ˜—šžœœœ ˜Bšœ˜Kšœ˜šœ œ˜Kš œœœœœ œ ˜8Kšœ œ9œ˜NKšœœ˜$šœœœ ˜ Kšœ œœ˜:Kšœ˜—Kšœœ˜3Kšœ˜—šœ œ˜Kš œœœœœ œ ˜8Jšœœ˜%šžœœœœœ œœ˜@Kšœœ˜—Kš œœœ œœœŸ˜MJš œ œœœœ ˜4Jšœœ,˜7Jšœœœ˜$Jšœ˜Kšœœ ˜/Kšœ˜—KšœœŸ˜%—Kšœ˜ —J˜Jšœœ1˜GJšœ œœ˜$J˜Jšœœ˜*Kšœ˜——…—(G