Private Data Stamp: No X:6.5" Y:11.25" Page Numbers: Yes X: 527 Y: -.5" First Page: 8 Heading:q(635)\b Mesa Pup Package Functional Specificationy756q\b Byte Stream interfacex4e30\b The Pup Package ByteStream (BSP) implementation uses a Stream interface that is different from the normal Mesa one defined in StreamDefs. See appendix A for a detailed description. This section only discusses the peculiarities of Pup ByteStreams.x4e12jk54 PupByteStreamCreate: PROCEDURE [ remote: PupAddress, ticks: Tocks] RETURNS [Stream.Handle];l4640d4268x4e12k54\f6b20f7 10f6 37f7 7f6 Tocks: TYPE = RECORD [CARDINAL];l4640d4268x4k54\f6b6f7 14f6 2f7 8f6 StreamClosing: ERROR [why: CloseReason, text: STRING];l4640d4268x4k54\f6b14f7 6f6 26f7 6f6 CloseReason: TYPE = { localClose, remoteClose, noRouteToNetwork, transmissionTimeout, remoteReject};l4640d4268x4k54\f6b12f7 5f6 PupByteStreamCreate is used to create a user end of a connection. It builds the necessary data structures and tries to open a connection to the specified remote address. StreamClosing will result if it can not be opened in a reasonable length of time.x4e12jk54\f6b19f0B153f6b13f0B If the connection gets into trouble for any reason, it is smashed closed, and any process that tries to do a get or put on the stream will run into the StreamClosing ERROR. text is likely to be NIL. If not, it is the text portion of the error or abort Pup provided by the remote end. localClose means that the stream is in the process of being deleted. If you ever get this, you are in trouble because you should not have any processes using a stream when you delete it. remoteClose means that the connection was closed by the remote machine. The other three reasons can also happen during PupByteStreamCreate. noRouteToNetwork means that the pup router does not know (any longer) how to get packets to the remote machine. Currently it isn't generated, but will probably reappear in the future. There are problems with transients in the routing tables. transmissionTimeout means that the remote machine has not responded within a reasonable amount of time. Maybe it has crashed, or if during PupByteStreamCreate, maybe it is not listening to the Ethernet. remoteReject means that the remote machine has explicitly rejected the connection or connection request. This frequently happens if the remote machine has been rebooted.x4e12jk54\152f6b13f0B1f7b5f0B3f6b4f0B17f7b3f0B89f6b10f0B179f6b11f0B109f6b19f0B3f6b16f0B97f1 130f0 2f6b19f0B121f6b19f0B46f6b12f0B If the remote end has requested an ack, the PupPackage normally defers sending it until the receiving process sucks up all the data from the buffer. (If it asks again, it will get a prompt reply. Well, it was supposed to, but due to a bug...) If the sender is slightly faster than the receiver, this slight delay greatly improves throughput by keeping the allocation window as large as possible, and hence minimizing the number of ack packets that need to be generated and processed.x4e12jk54\196f1 47f0 In addition to sending the current buffer, SendNow also requests that it be acknowledged. It will send an empty packet if necessary. This allows a bulk data transfer operation (FTP) to cooridinate it's (disk) activity with the (disk) activity of the process at the other end. Consider the case where the sender and receiver use the same size buffers, and the Pup buffers are slightly larger than the client buffers. Assume that it takes both ends roughly the same amount of time to generate and consume the data. Without the SendNow, the tail of the clump sits in the senders buffers while the sender is fetching the second clump, and the receiver waits. Early in sending the second clump, the allocation limit will be reached, and the sender must wait for the receiver to process the first clump before the receiver asks for more data to trigger sending the ack. SendNow provides a way to keep things synchronized. The result is that the sender and receiver get to overlap the (disk) processing of the data. The current implementation waits in SendNow for the ack to arrive. Unless the receiving process at the remote end has fallen behind, this is only a short time. In particular, it is much smaller that the time necessary to write several pages on the disk.x4e12jk54\43f6b7f0B41f1 42f0 397f6b7f0B334f6b7f0B140f1 36f7b7f1B212f0 Delete discards any partial buffer, if any, that has not yet been sent. This avoids bumping into StreamClosing again if you are cleaning up the connection after the remote end has crashed. If you want to send the data that might be buffered, be sure to call SendNow.x4e12jk54\f6b6f0B92f6b13f0B149f6b7f0B When you delete a stream, be sure that you don't have any other PROCESSes using it or the rug will get yanked out from underneath them.x4e12jk54\64f7b7f0B Creating a listener tells the Pup Package that the client program will accept RFCs for the local socket number (the Pup Package knows the host and network). A listener also answers echo pups if you want a polite way to discover if it is alive.x4e12jk54\156f1 88f0 CreatePupByteStreamListener: PROCEDURE [ local: PupSocketID, proc: PROCEDURE [Stream.Handle, PupAddress], ticks: Tocks, filter: PROCEDURE [PupAddress] _ DontReject] RETURNS [PupListener];l4640d4268x4e12k54\f6b28f7 10f6 29f7 9f6 52f7 9f6 28f7 7f6 Tocks: TYPE = RECORD [CARDINAL];l4640d4268x4k54\f6b6f7 14f6 2f7 8f6 DestroyPupListener: PROCEDURE [PupListener];l4640d4268x4k54\f6b19f7 10f6 PupListener: TYPE = ... ;l4640d4268x4k54\f6b13f7 4f6 DontReject: PROCEDURE [PupAddress];l4640d4268x4k54\f6b12f7 9f6 RejectThisRequest: ERROR [error: STRING];l4640d4268x4k54\f6b19f7 5f6 9f7 6f6 CreatePupByteStreamListener makes a ByteStream listener. local is the local socket number to listen on. To stop listening, call DestroyPupListener.x4e12jk54\f6b27f0B20i8I3f6b5f0B41b2B24f6b18f0B The user supplied procedure will be FORKed to once for each connection that is setup with the local socket number. (The new PROCESS gets Detached.) The client is expected to delete the connection eventually. The PupAddress passed to proc is the address of the other end of the connection. ticks is the timeout interval for get and put used for any streams that get created by the listener.x4e12jk54\36f7b4f0B85f7b7f0B6f6b6f0B67f6 4b10f0B11f6b4f0B53f6b5f0B Optionally, you can supply a procedure that may reject undesired connections. This is useful to keep a server from crashing because it runs out of resources. (The default doesn't reject anything.) To reject a connection, the filter procedure should raise the ERROR RejectThisRequest. The text will be sent back to the other end in an abort Pup. If the filter procedure returns the connection will be accepted.x4e12jk54\262f7b5f0B1f6b17f0B The Pup Package currently uses a very simple buffer allocation strategy. It allocates a fixed number of buffers for each half of each ByteStream. (It does the correct things if the other end allocates fewer buffers.) Thus it is easy to generate deadlocks. The default number is 5. (If you are counting buffers, don't forget the extra one that is being emptied/filled.) The default buffer pool size is 15. That is large enough to prevent lockups if a program uses both halves of a stream, or 2 halves of 2 streams. If you are tight on core and only using one half of a stream (at a time -- FTP is a good example), you should consider changing the buffer pool size.x4e12jk54 SetMaxAllocation: PROCEDURE [CARDINAL];l4640d4268x4e12k54\f6b17f7 10f6 2f7 8f6 SetMaxBufferSize: PROCEDURE [CARDINAL];l4640d4268x4k54\f6b17f7 10f6 2f7 8f6 SetMaxAllocation will change the allocation limit for any ByteStreams that are created in the future. SetMaxBufferSize will change the maximun number of bytes allowed in a data packet in case you want to use less than the default. Existing streams are not effected.x4e12jk54\f6b16f0B87f6b16f0B SetPinging: PROCEDURE [BOOLEAN];l4640d4268x4e12k54\f6b11f7 10f6 2f7 7f6 Normally, the PupPackage will try to verify that the remote end is still alive if the connection is idle for a minnute or so. If it has crashed, StreamClosing[transmissionTimeout] will eventually be generated. SetPinging will change this parameter for any ByteStreams that are created in the future. Again, existing streams are not effected.x4e12jk54\146f6b34f0B32f6b10f0B There are currently four occasions for Timeouts. First, when trying to open a connection, an ERROR will be generated in one minute. Second, after a connection is opened, it will be smashed closed in 1 minute if an allocate is not received. Third, while sending data, the connection will be closed if a packet is not acknowledged within about 3 minutes. The Pup ByteStream package uses an adaptive timeout heuristic, so it is impossible to predict the exact number of retransmissions. If the other end goes into the debugger or otherwise dies, the retransmission interval should stabilize at 5 seconds. Fourth, if a connection is idle for a minute, a ping (empty aData) will be generated. Thereafter, they will be generated at the normal retransmission rate until an answer is received. If an answer is not received within two more minutes, the connection will be smashed closed.x4e12jk54\94f7b5f0B Various other goodiesx4e30k792\b SetPupStormy: PROCEDURE [BOOLEAN];l4640d4268x4e12k54\f6b14f7 9f6 2f7 7f6 SetPupStormy controls the lightning option in the PupRouter. If lightning is on, then occasional packets going in or out will be thrown away to simulate transmission errors. This is very handy for debugging high level protocols. The default is off. This option is not included in TinyPup. If you need it, use FatPup.x4e12jk54\f6b12f0B14i9I216f1 33f7b7f1B23f7b6f1B1f0 UseAltoChecksumMicrocode: PROCEDURE;l4640d4268x4e12k54\f6b26f7 9f6 SetPupCheckit: PROCEDURE [BOOLEAN];l4640d4268x4k54\f6b15f7 9f6 2f7 7f6 The packet format for a Pup provides for a software checksum in addition to any error checking that the hardware provides. This is very useful for avoiding trashed files in spite of flakey hardware or sick gateways. Internally, there are 3 options: ignore, software, and microcode. The default is software. SetPupCheckit[FALSE] sets the switch to ignore. You should do this only if you really need to go faster and won't complain if your data gets corrupted occasionally. SetPupCheckit[TRUE] sets the switch to software. UseAltoChecksumMicrocode sets the switch to microcode. You should use this only if you are sure that the correct microcode is in the RAM. RunMesa.run loads the RAM correctly if you are running on an Alto with 2K of PROM or a 3K RAM. The reason that the default isn't to use the microcode if the configuration looks reasonable is to avoid confusion when run with programs that load special microcode. Beware of getting restarted on a machine with a different configuration after if you use UseAltoChecksumMicrocode and call MakeImage.x4e12jk54\251f6b6f0B2f6b8f0B6f6b9f0B18f6b8f0B3f6b14f7 5f6 1f0B20f6b6f0B121f6b14f7 4f6 1f0B20f6b8f0B3f6b24f0B20f6b9f0B81f1 3f0 25f1 3f0 52f1 4f0 9f1 3f0 1f1 168f0 91f6b24f0B10f6b9f0B SetLocalOnly: PROCEDURE [BOOLEAN];l4640d4268x4e12k54\f6b14f7 9f6 2f7 7f6 SetLocalOnly controls the activation of the normal Ethernet Driver. If it is on, a dummy device is used rather than the Ethernet Driver. This allows bugs to be reproduced slowly without the complications of random packets coming in over the ethernet at unscheduled times. Of course, you won't be able to talk to any other machines if localOnly is on, but you can talk to yourself. This is not included in TinyPup. If you need it, include LoopBackPlug in your config.x4e12jk54\f6b12f0B325f6b9f0B37f1 26f7b7f1B27f7b12f1B16f0 CaptureErrors: PROCEDURE [PROCEDURE[ERROR]];l4640d4268x4e12k54\f6b15f7 10f6 1f7 16f6 There are many internal consistency checks within the Pup Package. When a problem is detected, a procedure is called with an ERROR as an argument. (The ERROR is simply a convient way to get the compiler/system to generate a unique value. When an enumerated type is used, it is more time consuming to add a new category of problem to the list.) The default error handler simply dives into the debugger via CallDebuger from MiscDefs. If that happens to you, look at the stack. Its argument will get printed in english if you have enough symbols on your disk. If not, the SignalLister may help.x4e12jk54\126f7b5f0B23f7b5f0B250f6b11f0B6f6b8f0B142f6b12f0B GetDoStats: PROCEDURE RETURNS [BOOLEAN];l4640d4268x4e12k54\f6b12f7 17f6 2f7 7f6 The Pup Package includes a (compile time) optional statistics gathering facility. GetDoStats returns TRUE if it has been compiled in.x4e12jk54\83f6b10f0B9f7b4f0B InspectIncomingPups: PROCEDURE [BOOLEAN, PROCDURE [CARDINAL, PupBuffer]];l4640d4268x4e12k720\f6b21f7 10f6 1f7 29f6 9f7 1f6 InspectOutgoingPups: PROCEDURE [BOOLEAN, PROCDURE [CARDINAL, PupBuffer]];l4640d4268x4k54\f6b21f7 10f6 1f7 29f6 9f7 1f6 incomingPup: CARDINAL = 100;l5910d5538x4k54\f6b13f7 8f6 outgoingPup: CARDINAL = 101;l5910d5538x4k54\f6b13f7 8f6 zappedIncommingPup: CARDINAL = 102;l5910d5538x4k54\f6b20f7 8f6 zappedOutgoingPup: CARDINAL = 103;l5910d5538x4k54\f6b19f7 8f6 ShowPupBuffer: PROCEDURE [CARDINAL, PupBuffer];l4640d4268x4k54\f6b15f7 10f6 1f7 10f6 There are also hooks for inspecting each Pup as it goes in or out, and a routine that prints them. ShowPupBuffer is not part of the normal Pup Package. It lives in PupShow.bcd.x4e12jk54\100f6b13f0B4i3I InspectIncomingPups[TRUE,ShowPupBuffer] will print all incoming Pups. You can, of course, supply your own routine to print them in the format that you prefer and/or print only the interesting ones.x4e12jk54\f6b20f7 4f6 15f0B Watchersx4e32jk792\b The watcher concept has two ideas. First, it allows a client program to look at Pups arriving when there is no socket ready to receive them. This would allow it to fire up a listener when an RFC arrives, and not clutter up core or other resources by listening when there is no need.x4e12jk54\4i7I The second idea is to allow programs to pay attention to the Ethernet when the Pup Package is not really on. This saves a lot of core if there is no real need for the Pup Package. Again, if an RFC arrives, the Pup Package can be turned on and a listener started. (This has not been reimplemented since Mesa 3; If you need it, please let me know.)x4e12jk54 InspectStrayPups: PROCEDURE [ on: BOOLEAN, seeBroadCast: BOOLEAN, proc: PROCEDURE [PupBuffer] RETURNS [BOOLEAN]];l4640d4268x4e12k54\f6b18f7 9f6 2f7 1f6 4f7 9f6 14f7 9f6 6f7 9f6 13f7 7f6 2f7 7f6 If on is TRUE, then watching is started. If not, it is stopped. After watching has been started, proc will be called each time a Pup arrives for an unknown socket. If it is a broadcast Pup, then seeBroadCast must also have been TRUE at the last call to InspectStrayPups. The proc must not do anything to the buffer - in particular, do not call ReturnFreePupBuffer. If the proc returns TRUE, the Pup Package sends an Error Pup (with subtype no-socket) back to the sender if it is not a broadcast packet or an error Pup.x4e12jk54\3f6b2f0B4f7b4f0B86f6b4f0B95f6b12f0B21f7b4f0B21f6b16f0B7f6b4f0B65f6b19f0B10f6b4f0B9f7b4f0B PupDebugx4e32jk54\b There is also a set of debugging routines that are accessed via Menu commands in the Debugger. They only work if you are using FatPup. They are contained in PupDebug.bcd. It needs to be loaded into the Debugger's core image with a command line similar to the following:x4e12jk54 >XDebug PupDebug/ll4269x4e12jk54\1f6 It adds its own menu to the main menu stack. The various commands will print the routing table, the socket table, a summary of the buffer headers, summary of the packet contents, or the current contents of the counters maintained by the Stats Package.x4e12jk54 Name processing utilitiesx4e32jk792\b The Pup Package also provides a collection of commonly needed routines for translating names and addresses.x4e20jk62 GetPupAddress: PROCEDURE [POINTER TO PupAddress, STRING];l4640d4268x4e12k54\f6b15f7 9f6 2f7 10f6 13f7 6f6 PupNameLookup: PROCEDURE [POINTER TO PupAddress, STRING];l4640d4268x4k54\f6b15f7 9f6 2f7 10f6 13f7 6f6 EnumeratePupAddresses: PROCEDURE [ STRING, PROCEDURE [PupAddress] RETURNS [BOOLEAN] ], RETURNS [BOOLEAN];l4640d4268x4k54\f6b23f7 9f6 2f7 18f6 14f7 7f6 2f7 7f6 5f7 7f6 2f7 7f6 PupAddressLookup: PROCEDURE [PupAddress, STRING];l4640d4268x4k54\f6b18f7 9f6 14f7 6f6 PupNameTrouble: ERROR [e: STRING, code: NameLookupErrorCode];l4256x4e24k54\f6b16f7 5f6 5f7 6f6 29f0B NameLookupErrorCode: TYPE = {noRoute, noResponse, errorFromServer};l4256x4k54\f6b21f7 4f6 GetPupAddress first calls ParsePupAddressConstant, and if that fails, it calls PupNameLookup. PupNameLookup makes a special case check for a name of "ME" (both letters must be capitals). If so, it returns the address of the local machine. Otherwise it sends the text string to the name lookup server which is normally running on a nearby Gateway. Since a machine may have several addresses, PupNameLookup selects the best one of the answers returned.x4e6jk54\f6b13f0B13f6b23f0B30f6b13f0B3f6b13f0B287f6b13f0B There are three reasons why PupNameLookup may not be able to supply a reasonable answer. If so, it will generate the ERROR PupNameTrouble with a text string that might help a person and an error code that might be useful by a program. In the first case, noRoute, the information was received from the gateway, but there is no way to get to the target machine. In the second, noResponse, no name lookup server responded within a reasonable length of time. Unfortunately, the third case, errorFromServer, does not help a program much. The protocol does not supply error codes useful to programs, but the desired information is probably in the text string.x4e6jk54\28f6b13f0B77f7b5f0B1f6b14f0B118f6b7f0B115f6b10f0B102f6b15f0B If the socket number from the text string is not explicitly specified, the socket number in the PupAddress will not be updated. Be sure to initialize it!. This allows a program to initialize a default value that can easily be overridden for debugging by a person typing in a text string that is normally just a machine name.x4e6jk54\96f6b10f0B The text string is either the name of a machine or the actual address of the machine encoded as "#" for a machine on the local network, or "##" to specify an explicit network number. If you also want to specify the remote socket number use "+" or "##". is a text string registered in the file PUP-NETWORK.TXT on Ivy. , , and are octal numbers. See Ed Taft's memo, [Maxc]PupName.press, for the fine print.x4e6jk54\30i4I28i7I EnumeratePupAddresses is similar to PupNameLookup but it gives the client all of the addresses in the database in case there is more than one. This is useful for locating backup servers in case the primary one is down. The nearest addresses are presented first and the order in the name lookup database is preserved when there are several answers equally close. It an address is currently not reachable, the entry is still presented to the client. (PupNameLookup simply picks the first one.) Although it is possible to send and receive Pups from within the client supplied procedure (for example, to see if that machine is up) that should probably be avoided since the buffer that the answer arrived in (and others with duplicate answers if there is more than one name lookup server on the local network) is still tied up. If the client procedure returns TRUE, the rest of the entries are ignored. EnumeratePupAddresses returns FALSE if the client procedure never returns TRUE.x4e6jk54\f6b21f0B15f6b13f0B404f6b13f0B395f7b4f0B40f6b21f0B9f7b5f0B39f7b4f0B ParsePupAddressConstant: PROCEDURE [POINTER TO PupAddress, STRING] RETURNS [BOOLEAN];l4640d4268x4e12k54\f6b25f7 9f6 2f7 10f6 13f7 6f6 2f7 7f6 2f7 7f6 ParsePupAddressConstant tries to parse the text string into a network address. The string must be of the form #, ##, or ##. Since socket numbers may be 32 bits, the form | may also be used to specify a socket number. All numbers are octal. Invalid characters, oversize numbers and whatever merely return FALSE.x4e12jk54\f6b23f0B337f7b5f0B AppendPupAddress: PROCEDURE [STRING, PupAddress];l4640d4268x4e12k54\f6b18f7 9f6 2f7 6f6 AppendHostAddress: PROCEDURE [STRING, PupAddress];l4640d4268x4k54\f6b19f7 9f6 2f7 6f6 AppendMyName: PROCEDURE [STRING];l4640d4268x4k54\f6b14f7 9f6 2f7 6f6 AppendPupAddress appends a text translation of the specified address to the string. The format is net#host#soc, where soc may be more than 16 bits. All numbers are in octal. AppendHostAddress uses PupAddressLookup to translate the address into a name. If it runs into troubles, it calls AppendPupAddress. AppendMyName fabricates an address for the local machine, and then calls AppendHostAddress.x4e12jk54\f6b16f0B161f6b17f0B6f6b16f0B75f6b16f0B3f6b12f0B61f6b17f0B Although not really needed for name processing, GetHopsToNetwork is normally used along with other routines in this section, so it is described here.x4e24jk54\48f6b16f0B GetHopsToNetwork: PROCEDURE [PupNetID] RETURNS [CARDINAL];l4640d4268x4e12k54\f6b18f7 9f6 12f7 7f6 2f7 8f6 GetHopsToNetwork can be used to help you decide which machine you want to talk to. It returns a huge number if the network number is unreasonable or there is currently no way to get there from here. In the future, the Pup Package may be able to provide more information.x4e12jk54\f6b16f0B Packet utilitiesx4e30k792\b This section describes the basic things that client programs can do to packets and/or buffers. They will be used by client programs that interface at the Socket level.x4e20jk62 We have adopted the convention that fields in the buffer that can be simply read/written by client programs should be accessed directly for efficiency. Such fields include the pupType, the source and destination PupAddresses, and the data. A PupBuffer is an OVERLAID RECORD, so you can access the data portion of it as b.pupBytes[i] (a PACKED ARRAY OF Bytes), b.pupChars[i] (a PACKED ARRAY OF CHARACTERs) or b.pupWords[i] (an ARRAY OF WORDs). If your data is a RECORD (a very good idea) you can LOOPHOLE a POINTER to your record to be @b.pupBody. We have also provided a pair of simple routines to access the other interesting field - the length.x4e20jk62\177f6b7f0B6f6b6f0B5f6b11f0B1f6b10f0B21f6b9f0B7f7b15f0B46f6b13f0B4f7b12f0B1f7b2f6 5f0B4f6b13f0B4f7b12f0B1f7b2f6 1f7 9f0B6f6b13f0B5f7b13f0B23f7b6f0B28f7b8f0B3f7b7f0B22f6b10f0B SetPupContentsBytes: PROCEDURE [PupBuffer, CARDINAL];l4640d4268x4e12k54\f6b21f7 9f6 13f7 8f6 SetPupContentsWords: PROCEDURE [PupBuffer, CARDINAL];l4640d4268x4k54\f6b21f7 9f6 13f7 8f6 GetPupContentsBytes: PROCEDURE [PupBuffer] RETURNS [CARDINAL];l4640d4268x4k54\f6b21f7 9f6 13f7 7f6 2f7 8f6 DataWordsPerPupBuffer: PROCEDURE RETURNS [CARDINAL];l4640d4268x4k54\f6b23f7 9f6 1f7 7f6 2f7 8f6 There are two lengths involved here. pupLength is the total length of the pup in bytes, not words, and exists as a field in the packet. The contents length includes only the text supplied by the user. Today, pupLength is the contents length plus 22. Be sure not to overfill a buffer -- you will clobber the header of the next buffer. DataWordsPerPupBuffer can be used to determine the maximum number of words that will fit in the body of a Pup. There is no GetPupContentsWords because I couldn't think of anything reasonable to do if there was an odd number of data bytes in the Pup.x4e12jk54\38f6b9f0B31i20I113f6b9f0B119f6b21f0B103f6b19f0B Fine point: If somebody is playing with large buffers, and you expect your packets to be forwarded by a gateway, be sure to round down to 266 words (PupDefs.maxDataWordsPerGatewayPup) before deciding how full you can fill a buffer.x4e20jk62\f1 150f7b33f1B ReturnFreePupBuffer: PROCEDURE [PupBuffer];l4640d4268x4e12k54\f6b21f7 9f6 GetFreePupBuffer: PROCEDURE RETURNS [PupBuffer];l4640d4268x4k54\f6b18f7 9f6 1f7 7f6 ReturnFreePupBuffer is used to put a buffer back on the freeQueue. It must be called to return the buffers obtained from socket.get. GetFreePupBuffer obtains one buffer from the freeQueue. It will wait if there is not a buffer currently available. This is how a client program gets a buffer to give to socket.put.x4e12jk54\f6b19f0B37f6b9f0B57f6b10f0B3f6b16f0B29f6b9f0B117f6b10f0B The Pup Package builds (at PupPackageMake time) a pool of 15 buffers. The Ethernet driver uses two and GetFreePupBuffer always leaves two in reserve, so there are really only 11 left for all the active users to share. Pup byte streams allocate a default of five packets, so lockups are easily possible if you have several active streams. Note that each active half of a stream can use up to 6 buffers.x4e12jk54\27f6b14f0B63f6b16f0B SwapPupSourceAndDest: PROCEDURE [PupBuffer];l4640d4268x4e12k54\f6b22f7 9f6 SwapPupSourceAndDest exchanges the source and dest fields of the PupBuffer. It fixes up the new destination if the old destination Pup was broadcast. Of course, it only makes sense if the buffer contains a packet that was transmitted from some (probably different) machine.x4e12jk54\f6b20f0B15f6b6f0B5f6b4f0B MoveStringBodyToPupBuffer: PROCEDURE [PupBuffer, STRING];l4640d4268x4e12k54\f6b27f7 9f6 13f7 6f6 AppendStringBodyToPupBuffer: PROCEDURE [PupBuffer, STRING];l4640d4268x4k54\f6b29f7 9f6 13f7 6f6 MoveStringBodyToPupBuffer copies the contents of the STRING into the body of the PupBuffer and sets the length accordingly. It is handy for very simple protocols and is used by PupNameLookup. AppendStringBodyToPupBuffer appends the contents of the STRING into the body of the PupBuffer and adjusts the length accordingly. Both routines will call Glitch if the STRING is NIL or it won't fit in the buffer.x4e12jk54\f6b25f0B28f7b6f0B22f6b9f0B88f6b13f0B2f6b27f0B29f7b6f0B22f6b9f0B62f6b6f0B8f7b6f0B4f7b3f0B Socket interfacex4e30k792\b The lowest level of the Pup Package accessible to the user is the Socket interface. At this level packets are delivered only with some reasonable probability, and there is no guarantee that they will not arrive out of order or even twice. The functions performed at this level have to do only with delivery. There is still the idea of local ánd remote addresses, and there is a routing function which decides what to do with the packets depending on those addresses. The socket is basically an interface to that routing function, which makes its name known in the appropriate tables and allows multiple users to coexist in the same machine.x4e20jk62 PupSocket: TYPE = POINTER TO PupSocketObject;l4640d4268x4e12k54\f6b11f7 17f6 PupSocketObject: TYPE = RECORD [ put: PROCDURE [PupBuffer], get: PROCDURE RETURNS [PupBuffer], setRemoteAddress: PROCDURE [PupAddress], getLocalAddress: PROCDURE RETURNS [PupAddress] ];l4640d4268x4k54\f6b17f7 13f6 8f7 8f6 19f7 16f6 32f7 8f6 32f7 16f6 The Socket Operations are:x4e12jk54 PupSocketMake: PROCEDURE [ local: PupSocketID, remote: PupAddress, ticks: Tocks] RETURNS [PupSocket];l4640d4268x4e12k54\f6b15f7 9f6 57f7 7f6 Tocks: TYPE = RECORD [CARDINAL];l4640d4268x4k54\f6b6f7 14f6 2f7 8f6 PupSocketMake creates the data structures necessary to communicate to the specified destination. It initiates no actual communications. If fillInSocketID is specified for the local socket number, a pseudo unique random socket number will be assigned.x4e12jk54\f6b13f0B128f6b14f0B PupSocketDestroy: PROCEDURE [PupSocket];l4640d4268x4e12k54\f6b18f7 9f6 PupSocketDestroy reclaims the data structures used by a socket and removes the socket from the routing tables.x4e12jk54\f6b16f0B socket.put[b];l4640d4268x4e12k54\f6b11i1I2f0B socket.put sends the buffer to the previously specified destination. Any problems encountered are ignored. When the buffer has been sent, which is normally right away, but may take several seconds, the client's requeue procedure is called. The requeue procedure lives in b.requeueProcedure. It is initialized to ReturnFreePupBufffer by GetFreePupBuffer. If you want to keep a buffer so that you can retransmit it (or otherwise reuse it) you must store something into b.requeueProcedure. If you do use your own requeue procedure, be sure that the buffer is eventually returned via ReturnFreePupBuffer.x4e12jk54\f6b10f0B264f6bi1f0BI1f6b16f0B24f6b20f0B4f6b16f0B116f6bi1f0BI1f6b16f0B96f6b19f0B PupBuffer _ socket.get[];l4640d4268x4e12k54\f6bi9I16f0B socket.get returns a buffer containing the next packet that is sent to the socket's local socketID. The Pup Package does not do any filtering on the source address, so you will get packets from unexpected places. When you are finished processing the buffer, you should call ReturnFreePupBufffer. If a packet does not arrive before the specified timeout, NIL is returned instead. Note that the Pup may have come from anywhere, the remote address is only used for sending. If you care, you should check the source of the Pup.x4e12jk54\f6b10f0B266f6b20f0B61f7b3f0B socket.setRemoteAddress[PupAddress];l4640d4268x4e12k54\f6b24i10I2f0B socket.setRemoteAddress changes the destination used by socket.put. Until it is changed again, all Pups send via socket.put will go to the specified address.x4e12jk54\f6b23f0B33f6b10f0B48f6b10f0B PupAddress _ socket.getLocalAddress[];l4640d4268x4e12k54\f6bi10I28f0B socket.getLocalAddress returns the local address of a socket. This tells you two things. One, if you used fillInSocketID for the local socket number when you created the socket, it will tell you the actual socket number that is in use. Second, if you have more than one hardware interface on your machine, it will tell you which one is the best path.x4e12jk54\f6b22f0B86f6b14f0B The normal sequence of operations is to make a socket and then, enter a loop that gets a PupBuffer from the freeQueue, fills it in, sends it, waits for a reply, processes the incoming PupBuffer, and returns it to the freeQueue. Finally, when finished, don't forget to delete the socket. It is quite reasonable to have two PROCESSes, one to look at incoming packets and another to send things out. Even if you don't expect any incoming data, be sure to have some PROCESS getting packets occassionally or buffers will pile up there if anybody ever does send you something. It is quite likely that error pups will be returned if a Gateway runs out of buffers, or the other end ever gets confused, rebooted, or ....x4e12jk54\89f6b9f0B10f6b9f0B67f6b9f0B24f6b9f0B98f7b7f0B134f7b7f0B There are two other routines that are useful for sending Pups. In both cases the client program must fill in the source and destination socket numbers.x4e12jk54 PupRouterBroadcastThis: PROCEDURE [PupBuffer];l4640d4268x4e12k54\f6b24f7 9f6 PupRouterSendThis: PROCEDURE [PupBuffer];l4640d4268x4k54\f6b19f7 9f6 PupRouterBroadcastThis will broadcast a Pup on all directly connected networks. The Pup Package will provide the correct destination net, source host, and source net numbers for each network as the Pup is transmitted.x4e12jk54\f6b22f0B NB: Do not use the broadcast facility indiscriminately. Random undesired packets can have a severe performance impact on some programs. In general, it should only be used to locate a machine that you want to comunicate with.x4e12jk54\b3B PupRouterSendThis is the simplest way to send a packet. Don't forget to fill in the source socket, destination address, pupType and set the length. The Pup Package will fill in the correct source net and host numbers. There is a special case check for a destination host of allHosts (0) and a destination net of allNets (0). If so, the buffer is handed off to PupRouterBroadcastThis. If you specify allHosts and a non 0 network, the Pup is a directed broadcast, and it will be broadcast on that specific network, and not on all directly connected networks. There is no way to broadcast a Pup on network 0 without broadcasting it on the other networks too.x4e12jk54\f6b17f0B260f6b8f0B30f6b7f0B42f6b22f0B18f6b8f0B SendPup: PROCEDURE [b: PupBuffer, type: PupType, bytes: CARDINAL];l4640d4268x4e12k54\f6b9f7 9f6 38f7 8f6 ReturnPup: PROCEDURE [b: PupBuffer, type: PupType, bytes: CARDINAL];l4640d4268x4k54\f6b11f7 9f6 38f7 8f6 SendPup fills in the pupType and the length of the buffer, and then calls PupRouterSendThis. ReturnPup calls SwapPupSourceAndDest and then calls SendPup.x4e12jk54\f6b7f0B67f6b17f0B3f6b9f0B7f6b20f0B16f6b7f0B SendErrorPup: PROCEDURE [PupBuffer, PupErrorCode, STRING];l4640d4268x4e12k54\f6b14f7 9f6 27f7 7f6 SendErrorPup treats the buffer as a Pup that was sent to this machine, converts it into an Error Pup with the specified error code and text, and sends it back to the original source. The buffer must have been sent to this machine since SendErrorPup needs to know the network address through which the packet arrived, so don't pass it a buffer that you obtained from GetFreePupBuffer. If STRING is NIL, a built in list of defaults is searched. Actually, the buffer isn't sent if it is already an error Pup, or if it is a broadcast Pup.x4e12jk54\f6b12f0B225f6b12f0B118f6b16f0B6f7b6f0B4f7b3f0B  Tock conversionx4e30k792\b There are several routines in the Pup Package that normally WAIT until something has happened. The argument to the routines that setup the wait times is a simple record.x4e20jk62\60f7b4f0B Tocks: TYPE = RECORD [CARDINAL];l4640d4268x4e12k54\f6b6f7 14f6 2f7 8f6 veryLongWait: Tocks = [177777B];l5910d5538x4k54\f6b13f7 1f6 5f7 3f6 1f7 7f6 veryShortWait: Tocks = [0];l5910d5538x4k54\f6b14f7 1f6 5f7 3f6 1f7 1f6 veryLongWait is used to disable timeouts completely. veryShortWait is used to avoid waiting at all. All other values are passed directly to ProcessDefs.SetTimeout.x4e20jk62\f6b12f0B42f6b13f0B75f6b22f0B SecondsToTocks: PROCEDURE [CARDINAL] RETURNS [Tocks];l4640d4268x4e12k54\f6b15f7 29f6 MsToTocks: PROCEDURE [CARDINAL] RETURNS [Tocks];l4640d4268x4k54\f6b10f7 29f6 These routines simply do a bit of arithmetic and the appropriate TYPE conversion. Their input is in seconds and milliseconds respectively. Note that it is not possible to specify wait times longer than about a minute in milliseconds.x4e20jk62\65f7b4f0B Queue operationsx4e30k792\b The Pup Package provides a simple FIFO Queue Package which may be useful if you are operating at the socket level. NB: The Queue Package does not provide any locks against preemption. The client is expected to call the queue routines from within an appropriate MONITOR.x4e20jk62\143i3I117f7b7f0B Queue: TYPE = POINTER TO QueueObject;l4640d4268x4e12k54\f6b7f7 17f6 QueueObject: TYPE = RECORD [length: CARDINAL, ...];l4640d4268x4k54\f6b13f7 13f6 10f7 8f6 length is the number of buffers currently on the queue. It is handy for various heuristics. In particular, you may want to check for an empty queue before calling DequeuePup if you are worried about performance.x4e12jk54\f6b6f0B159f6b10f0B QueueInitialize: PROCEDURE [Queue];l4640d4268x4e12k54\f6b17f7 9f6 QueueCleanup: PROCEDURE [Queue];l4640d4268x4k54\f6b14f7 9f6 QueueInitialize simply initializes the data structures within a QueueObject allocated by the caller. It must be called before any other queue operations reference the QueueObject. QueueCleanup returns any buffers on the queue to the freeQueue and marks it as invalid. You must call QueueInitialize again before reusing the queue.x4e12jk54\f6b15f0B49f6b11f0B93f6b11f0B3f6b12f0B41f6b9f0B41f6b15f0B EnqueuePup: PROCEDURE [Queue, PupBuffer];l4640d4268x4e12k54\f6b12f7 9f6 DequeuePup: PROCEDURE [Queue] RETURNS [PupBuffer];l4640d4268x4k54\f6b12f7 9f6 9f7 7f6 ExtractPupFromQueue: PROCEDURE [Queue, PupBuffer] RETURNS [PupBuffer];l4640d4268x4k54\f6b21f7 9f6 20f7 7f6 EnqueuePup puts a PupBuffer onto the tail of a queue. DequeuePup takes a PupBuffer off of the head of a queue. If the queue is empty, it returns NIL. ExtractPupFromQueue pulls a specified buffer out of the middle of a queue. If the buffer is not on the queue, it returns NIL.x4e12jk54\f6b10f0B8f6b9f0B28f6b10f0B9f6b9f0B64f7b3f0B3f6b19f0B103f7b3f0B QueueLength: PROCEDURE [Queue] RETURNS [CARDINAL];l4640d4268x4e12k54\f6b13f7 9f6 9f7 7f6 2f7 8f6 QueueEmpty: PROCEDURE [Queue] RETURNS [BOOLEAN];l4640d4268x4k54\f6b12f7 9f6 9f7 7f6 2f7 7f6 These are just fast, clean, and simple ways to see if there is anything in a Queue.x4e12jk54\77f6b5f0B Bugs and gremlinsx4e30k792\b Note that most program bugs do not show up as uncaught SIGNALs, but instead call an error handler, which defaults to a routine that calls the debugger. If you suddenly end up in the debugger with a "PupGlitch" message, look at the stack. If you find Glitch, look at its parameter. If you have enough symbols on your disk the name will usually be reasonably clear what the problem is. If not, consult a friend or dig out the listings. Glitches are problems from which it is not reasonable to recover. Usually, they are caused by bugs in the client program and/or inadequate documentation. If you get one, you should not attempt to continue execution of your program. Because of various validity checks in the Pup Package, core clobbers frequently show up as Pup Glitches.x4e20jk62\55f7b7f0B190f6b6f0B Signalsx4e30k62\b Except for the EFTP routines, the following summary is an exhaustive list of the signals explicitly generated by the Pup Package. It does NOT include signals generated from within the system when the Pup Package calls a system routine. They all represent well understood circumstances, and even if you didn't want the signal at that time, the Pup Package knows what is going on and is passing the problem back to the client program where it belongs.x4e20jk62 Stream.Timeout: SIGNAL;l4269x4e18k122\f6b16f7 6f6 Stream.Timeout is generated by the ByteStream input routines if enough data does not arrive in time. The actual wait times are not very accurate.x4e8jk62\f6b14f0B StreamClosing: ERROR [why: CloseReason, text: STRING];l4269x4e18k122\f6b15f7 5f6 26f7 6f6 CloseReason: TYPE= {localClose, remoteClose, transmissionTimeout, noRouteToNetwork, remoteReject};l4269x4k122\f6b13f7 4f6 StreamClosing is generated by ByteStreamOpen when the remote site explicitly rejects the connection, does not accept it in time, or there is not any way to get a packet to the remote site. (Currently, the timeout is about 60 seconds.)x4e8jk62\f6b13f0B17f6b14f0B After a stream is opened, StreamClosing is activated by many ByteStream routines whenever an attempt to use a connection is made after the Pup Package connection has been closed. It may be closed by the remote end, or automatically by the Pup Package when it discovers some problem. The connection is closed automatically when ever the remote end explicitly rejects a packet (maybe it has been rebooted) or whenever a packet is not acknowledged soon enough (maybe it is in the debugger). On input, all the data from the remote site is processed before activating the StreamClosing ERROR.x4e8jk62\26f6b13f0B531f6b13f0B1f7b5f0B PupNameTrouble: ERROR [e: STRING, code: NameLookupErrorCode];l4640d4268x4e24k54\f6b16f7 5f6 5f7 6f6 29f0B NameLookupErrorCode: TYPE = { noRoute, noResponse, errorFromServer};l4640d4268x4k54\f6b PupNameTrouble is only generated by EnumeratePupAddresses and PupNameLookup and GetPupAddress which call it, and PupAddressLookup. There are 3 reasons why EnumeratePupAddresses or PupAddressLookup may not be able to supply a reasonable answer. If so, it will generate the ERROR PupNameTrouble with a text string that might help a person and an error code that might be useful by a program. In the first case, noRoute, the information was received from the name server, but there is no way to get to the target machine. In the second, noResponse, no name lookup server responded within a reasonable length of time. Unfortunately, the third case, errorFromServer, does not help a program much. The protocol does not supply error codes useful to programs, but the desired information is probably in the text string.x4e6jk54\f6b14f0B22f6b21f0B5f6b13f0B5f6b13f0B14f6 6b16f0B27f6b21B4b16f0B77f7b5f0B1f6b14f0B118f6b7f0B119f6b10f0B102f6b15f0B