RFC 713
MSDTP-Message Services Data Transmission Protocol
Request for Comments: 713 ๐
Okay bestie, let's start with the title block ๐ This one is RFC 713, written by Jack Haverty (JFH@MIT-DMS) with NIC #34739, dated Apr 1976. The original doesn't name a category, and it doesn't say this RFC obsoletes or updates anything. Just a clean little header, no drama ๐
I. ABSTRACT โจ
So the big idea is that message servers need a way to move data between hosts. This mechanism is called the MSDTP, and ngl it's basically a translator ๐ฆ It's defined as a process that converts between two sets of items: abstract entities like 'strings' and 'integers', and the formats used to show that data as a byte stream.
The author also describes a proposed way to organize a general data transfer mechanism, and shows how the MSDTP would be used in that setup ๐ซถ
II. REFERENCES ๐
The author clearly did their homework, so here's the full reading list ๐ค
- Black, Edward H., "The DMS Message Composer", MIT Project MAC, Programming Technology Division Document SYS.16.02.
- Burchfiel, Jerry D., Leavitt, Elsie M., Shapiro, Sonya and Strollo, Theodore R., compilers, "Tenex Users' Guide", Bolt Beranek and Newman, Cambridge, Mass., May 1971, revised January 1975, Descriptive sections on the TENEX subsystems: MAlLER, p. 116-11; MAlLSTAT, p. 118-119; READMAIL, p. 137; and SNDMSG, p. 165-170.
- Haverty, Jack, "Communications System Overview", MIT Project MAC, Programming Technology Division Document SYS.16.00.
- Haverty, Jack, "Communications System Daemon Manual", MIT Project MAC, Programming Technology Division Document SYS.16.01.
- ISI Information Automation Project, "Military Message Processing System Design," Internal Project Documentation (Out of Print), Jan. 1975
- Message Services Committee, "Interim Report", Jan. 28, 1975
- Mooers, Charlotte D., "Mailsys Message System: Manual For Users", Bolt Beranek and Newman, Cambridge, Mass., June 1975 (draft).
- Myer, Theodore H., "Notes On The BBN Mail System", Bolt Beranek and Newman, November 8, 1974.
- Myer, Theodore H., and Henderson, D. Austin, "Message Transmission Protocol", Network Working Group RFC 680, NIC 32116, April 30, 1975.
- Postel, Jon, "The PCPB8 Format", NSW Proposal, June 5, 1975
- Tugender, R., and D. R. Oestreicher, "Basic Functional Capabilities for a Military Message Processing Service," ISI?RR-74-23., May 1975
- Vezza, Al, "Message Services Committee Minority Report", Jan. 1975
III. OVERVIEW ๐ฆ
This doc describes a mechanism built for message servers that talk over an eight-bit byte-oriented network connection. Its job is to move data structures and their data-typing info around. The author shares it in the hope that other projects who need to move data structures between dissimilar hosts can use it too ๐
It starts with a set of abstract entities called PRIMITIVE ITEMS. These are meant to cover the traditional, generally useful data types, like integers, strings, and arrays ๐
There's also a mechanism for adding to that set of abstract data entities, so you can bring in application-specific data. Its format and meaning are understood by the programs involved, but it can still be sent using the common coding facilities. Examples would be a 'file specification' or a 'date'. These are called SEMANTIC ITEMS, because they usually carry data with semantic meaning inside the application ๐
Semantic and primitive items are collectively called ITEMS.
Next, the protocol defines the byte stream format used to send items from machine to machine. These encodings are described in terms of OBJECTS, which are the actual byte streams sent over the wire.
To finish the protocol, the rules for translating between objects and items are given as each object is defined โจ
So here's how it works: an item gets translated into an object, sent over the connection as a stream of bytes, and rebuilt as an item on the other side. The protocol is basically a simple translator ๐ง It lists a set of abstract entities (the items, which programmers know about), a set of byte-stream entities (the objects), and the rules for converting between the two. A site running the MSDTP would usually provide a way to convert between objects and the local representation of each item. Applications then define their interactions using items, without caring how those items are represented on each machine. So a program can work with something high-level like a character string, without worrying about all the different formats it could take. The MSDTP handles that part ๐
Finally, the author discusses a general data transfer mechanism for communication between programs, and how this particular byte-oriented protocol would be used in that environment.
Terminology gets defined and highlighted by capitalizing as it's introduced. Keep an eye out for that ๐
IV. PRIMITIVE DATA ITEMS ๐
The primitive data items cover a bunch of traditional, well-understood types, like integers and strings. Each one gets a mnemonic name starting with the character pair "p-", as a reminder that it's primitive ๐
These items can be represented in whatever way the computer systems' programmers want. No judgment ๐ซถ
IV.1 -- Set Of Primitive Items
The primitive items defined here are p-INT, p-STRING, p-STRUC, p-BITS, p-CHAR, p-BOOL, p-EMPTY, and p-XTRA.
Since the protocol was mainly built for message services, items like p-FLOAT aren't included, because they weren't needed. More items can easily be added when necessary โจ
A p-INT does the classic job of representing integers. A p-BITS (BIT Stream) represents a bit stream. The two possible p-BOOL (BOOLean) items represent the logical values *TRUE* and *FALSE*. The single p-EMPTY item is for things like showing that a field in a message is empty. It acts as a placeholder for 'no data', and it shows up as *EMPTY* ๐
The p-STRUC (STRUCture) item groups a collection of items together as one value, and keeps the order of the elements. For example, a p-STRUC of p-INTs ๐
A p-CHAR is one character. Most character data will show up as p-STRINGs, though. A p-STRING should be considered a synonym for a p-STRUC that holds only p-CHARs. This matters for generality and consistency, especially when you're defining operations on structures, like pulling out subsequences of elements ๐ฆ
Four p-XTRA items can be sent in a single byte. They're there for higher-level protocols to use when a common datum can be represented just by its name. For example, an acknowledgment between two servers. Using p-XTRAs for things like that means they can be handled in one byte. The four possible p-XTRA items are *XTRA0*, *XTRA1*, *XTRA2*, and *XTRA3*. User protocols can give them whatever meanings they want ๐
IV.2 -- Printing Conventions
The author introduces these printing conventions so the primitive items are easier to talk about ๐
When a specific instance of a primitive item shows up, it's written in a traditional representation for that kind of data. So p-INTs look like sequences of digits, e.g. 100, and p-STRINGs look like characters wrapped in double quotes, for example "ABCDEF".
Like we saw above, the two possible p-BOOL items are written as *TRUE* or *FALSE*. The object p-EMPTY is written as *EMPTY*. A bit stream (p-BITS) looks like a string of 1s and 0s wrapped in asterisks, for example *100101001*. A p-CHAR is written as the character in single quotes, e.g. 'A' ๐ธ
p-STRUCs are written as their elements' representations inside parentheses, for example (1 2 3 4), ("XYZ" "ABC" 1 2), or ((1 2 3) "A" "B"). Heads up: since p-STRINGs are just a special class of p-STRUCs, with their own name and printing format for brevity and convenience, the items "ABC" and ('A' 'B' 'C') are identical. The second format should not be used ๐
To describe a generic p-STRUC, like when you're specifying the format of something's contents, you write the items as a mnemonic name, optionally followed by a colon and the permitted types of values for that datum. When more than one item can be the value for a component, the options are separated by vertical bars. For example, p-INT|p-STRING means a single item that's either a p-INT or a p-STRING ๐ง
To represent a sequence of items, the author uses the Kleene star convention. p-INT[*] means any number of p-INTs. p-INT[3,5] means from 3 to 5 p-INTs. p-INT[*,5] means up to 5, and p-iNT[5,*] means at least 5 p-INTs ๐
For example, a p-STRUC used to carry names and numbers might be specified like this:
(name:p-STRING number:p-INT)
And when you're talking about items in general, and not a specific value, you can use the name and type format. So offset:p-INT is used to talk about an 'offset' that has a numeric value ๐
V. SEMANTIC ITEM MECHANISM ๐ฅ
The semantic item mechanism gives program designers a way to use all kinds of application-specific data items. Main character energy ๐
This mechanism uses a special tagged structure. It carries the data type info along with the actual components of the particular semantic item. For discussion purposes. That special p-STRUC is called a p-EDT (Extended Data Type) โจ
When p-EDTs are transferred, their identity as a p-EDT is kept. That way, the application program gets the matching semantic item instead of a plain p-STRUC. Other than that, a p-EDT is identical to a p-STRUC in every way ๐ซถ
V.1 -- Format of p-EDTs
Here's a prototypical p-EDT. It's printed the same way as a normal p-STRUC. Since p-EDTs get converted into semantic items before they're shown to the user, a p-EDT never gets used outside this protocol definition ๐ฆ
(type:p-INT|p-STRING version:p-INT com1:any
com2:any ...)
The first element, the 'type', is usually a p-INT, and it identifies the specific type of semantic item. Types get numeric codes assigned in a controlled way. The type can also be a p-STRING instead, which lets people develop new data types before they get a code. Each type has an equivalent p-STRING name. These can be used interchangeably as 'type' elements, mostly to keep upward compatibility ๐
The second element of a p-EDT is always a p-INT, the 'version'. It sets the exact format of the particular datum. A semantic item can go through several revisions of its internal structure, and assigning a different version to each revision makes those changes visible ๐
Next come the 'com' elements, if there are any. They carry the actual data of the semantic item. Each semantic item's definition explains what values are allowed for these components and how to read them. Those definitions can use any item types to describe the semantic item's format. But lower-level concepts, like objects, are off-limits in these definitions. Not allowed ๐ซ
Semantic items get printed as the type's mnemonic, with the character pair "s-" in front, so you can tell the data item is handled by this mechanism ๐
V.2 -- Printing Conventions
A semantic item basically looks like a p-STRUC with just its components (if there are any), except it's introduced by the
semantic type name and a # character ๐ (basically the spell that makes the item a semantic item, bestie ๐ฆ). If nobody says which version you're on, it's assumed to be 1 ๐ธ. For later versions, you stick the version number right onto the type name, so FILE-2 means version 2 of the FILE data type ๐
Say we make a semantic item called a 'file specification' with two components, a host number and a pathname ๐. A specific one could look like this:
#FILE(69 "DIRECTORY.NAME-OF-FILE")
and a generic s-FILE would be shown like this:
#FILE(host:p-INT|p-STRING pathname:p-STRING)
So 'host' is the first component, and it can be either a p-INT or a p-STRING. 'pathname' is the second component, and it must be a p-STRING ๐ง The full definition would spell out the interpretation rules for these components too.
VI. ENCODING OBJECTS โจ
This section is the list of objects used to represent items as byte streams for sending between servers ๐ฆ Objects get called by mnemonic type-names with "b-" in front, which tells you they only exist as byte streams ๐
All servers are required to be capable of decoding the entire set of objects. Servers are not required to transmit certain objects, though, because those are there to boost channel efficiency ๐
The encodings are designed to make life easier for programmers and to speed up the receiving decoder ๐ In every case, the type and the length in bytes of an object come first, and that's a big deal for implementing stuff ๐ญ The type lets a decoder get built in a modular way. The best perk of including the size is that the receiver always knows how many bytes to read to figure out what's next, and knows exactly when each object ends. That kills a whole bunch of timing and synchronization headaches ๐ซถ
Two varieties of objects are defined. The first is called ATOMIC, and it holds the objects used to encode the most common data efficiently โจ The second is NON-ATOMIC, used for bigger or less common items ๐
In every case, a data object begins with a single byte called the TYPE-BYTE, and one field of that byte holds the type code of the object ๐ Any following bytes are read according to the type involved.
VI.1 -- Presentation Conventations ๐
When we talk about the formats of bytes, here's the deal. The individual bits get referenced with capital letters from A to H, where A is the highest-order bit and H is the lowest ๐ The entire eight-bit value could be called ABCDEFGH, and subfields get identified the same way. So the CDEF field is the middle four bits of a byte ๐ฆ
When we talk about field values, we use binary, and small letters near the end of the alphabet stand for particular bits we're discussing ๐ง For example, we could say the BCD field of a byte holds a specifier for some type, and define its value as BCD=11z. Then we could refer to the z=1 case and the z=0 case as shorthand for BCD=111 and BCD=110 respectively ๐ธ
V1.2 -- Type-Byte Bit Assignment โจ
To help you get the type-byte values, here's a table and a graph showing all eight bits ๐
OXXXXXXX -- CHAR7 (CHARacter, 7 bit)
10XXXXXX -- SINTEGER (Small INTEGER)
l10XXXXX -- NON-ATOM (NON-ATOMic objects)
11100XXX -- LINTEGER (Large INTEGER)
11101XXX -- reserved
11110XXX -- SBITSTR (Short BIT STReam)
111110XX -- XTRA (eXTRA single-byte objects)
1111110X -- BOOL (BOOLean)
11111110 -- EMPTY (EMPTY data item)
11111111 -- PADDING (unused byte)
In each case, the bits marked X hold information specific to the type involved, and that gets explained when each type is defined ๐
Here's an equivalent tree for anyone who prefers it ๐ณ
start with high order bit
|
|
|
0-----0-----0-----0-----0-----0-----0-----0-----X
| | | | | | | | PADDING
0| 0| 0| 0| 0| 0| 0| 0|
| | | | | | | |
X | X | X | X X
CHAR7 | NON-ATOM | BITS | BOOL EMPTY
(7) | (5) | (3) | (1)
| 0| | |
SINTEGER | XTRA
(6) | (2)
LINTEGER
(3)
Type-Byte Bit Assignment Scheme
Read the picture by starting at the top and taking the right branch at each node for the next bit of the type-byte as you scan from left to right ๐ค๏ธ When a type is assigned, the branch ends in an X with the name of the type, and the number of remaining bits in parentheses. Each individual object definition spells out how those bits get used ๐
V1.3 -- Atomic Objects ๐ง
Atomic objects are identified by specific patterns in a type-byte. Receiving servers must be capable of recognizing and handling all atomic types, since the size of the object isn't explicitly present in a uniform fashion ๐ซถ
Atomic Object: B-CHAR7
The b-CHAR7 (CHARacter 7 bit) object exists to send characters in 7-bit ASCII ๐ Since the vast majority of message-related data is made of these, they're built to be super efficient to transmit โจ Other formats, like eight-bit values, can be introduced as non-atomic objects. Here's the format of a b-CHAR7:
A=0 identifying the b-CHAR7 data type
BCDEFGH=tuvwxyz containing the character
code
The tuvwxyz bits contain the ASCII code of the character. For example, sending a "space" (ASCII code 32, 40 octal) would use this byte:
00100000
ABCDEFGH
A=0 flags this byte as a b-CHAR7, and the remaining bits carry the 7-bit code, octal 40, for space ๐ธ
A b-CHAR7 standing alone is presented as a p-CHAR. That'll probably be rare, if it happens at all ๐ The most common use of b-CHAR7s is as elements of b-USTRUCs used to send p-STRINGS, which gets explained later ๐
Atomic Object: B-SINTEGER
The b-SINTEGER (Small INTEGER) object sends very small positive integers, with values up to 64 ๐ง It always translates to a p-INT, and any p-INT between 0 and 63 may be encoded as a b-SINTEGER for transmission. Here's the format of a b-SINTEGER:
AB=10 identifying the object as a b-SINTEGER
CDEFGH=uvwxyz containing the actual number
For example, to transmit the integer 10 (12 octal), the following byte would be transmitted:
10001010
ABCDEFGH
AB=10 specifies a b-SINTEGER. The remaining six bits contain the number 10 expressed in binary ๐
Atomic Object: B-SINTEGER
The b-SINTEGER (Large INTEGER) object sends p-INTs to any precision up to 64 bits ๐ It is always translated as a p-INT. Sending servers are permitted to choose either b-SINTEGER or b-SINTEGER format for transmission of numbers, as appropriate. When possible, b-SINTEGERs can be used for better channel efficiency. The format of a b-SINTEGER follows:
ABCDE=11100 specifying that this is a b-SINTEGER.
FGH=xyz containing a count of number of bytes to follow.
The xyz bits are interpreted as a number of bytes to follow, which contain the actual binary code of the integer in 2's complement format. Since a zero-byte integer is disallowed, the pattern xyz=000 is interpreted as 1000, specifying that 8 bytes follow ๐คฏ The number is transmitted with high-order bits first. This format permits transmission of integers as large as 64 bits in magnitude.
For example, if the number 4096 (10000 octal) is to be transmitted, the following sequence of bytes would be sent:
11100010 00010000 00000000
ABCDEFGH ---actual data---
ABCDE=11100, identifying this as a b-LINTEGER, E=0, specifying a positive number, and FGH=010, specifying that 2 bytes follow, containing the actual binary number ๐ฆ
Atomic Object: B-SBITSTR
The b-SBITSTR (Short BIT STReam) object is used to transmit a p-BITS of length 63 or less ๐ For longer bit streams, the non-atomic object b-LBITSTR may be used. The format of a b-SBITSTR follows:
ABCDE=11110 specifying the type as b-SBITSTR
FGH=xyz specifying the number of bytes
following.
The xyz value specifies the number of additional bytes to be read to obtain the bit stream values. As in the case of b-SINTEGER, the value xyz=000 is interpreted as 1000, specifying that 8 bytes follow.
To avoid requiring you to specify exactly how many bits are contained, the following convention is used. The first data byte is scanned from left to right until the first 1 bit is encountered. The bit stream is defined to begin with the immediately following bit, and run through the last bit of the last byte read. In other words, the bit stream is 'right-adjusted' in the collected bytes, with its left end delimited by the first 'on' bit ๐ฏ
For example, to send the bit stream 001010011 (9 bits), the following bytes are transmitted:
11110010 00000010 01010011
ABCDEhij klmnopqr stuvwxyz
The hij=010 value specifies that two bytes follow. The q bit, which is the first 1 bit encountered, identifies the start of the bit stream as being the r bit. The rstuvwxyz bits are the bit stream being handled ๐
Atomic Object: b-BOOL
The b-BOOL (BOOLean) object is used to transmit p-BOOLs. The format of b-BOOL objects follows:
ABCDEFG=1111110 specifying the type as
b-BOOL
H=z specifying the value
The two possible translations of a b-BOOL are FALSE and TRUE โ
11111100 represents *FALSE*
11111101 represents *TRUE*
ABCDEFGz
If z=0, the value is FALSE, otherwise TRUE.
Atomic Object: B-EMPTY
The b-EMPTY object type is used to transmit a 'null' object, i.e. an EMPTY. The format of a b-EMPTY follows:
ABCDEFGH=11111110 specifying *EMPTY*
Atomic Object: B-XTRA
The b-XTRA objects are used to carry the four possible p-XTRA items, i.e., XTRA0, XTRA1, XTRA2, and XTRA3 ๐ง These four items correspond to the binary coding of the remaining two bits after the b-XTRA type code bits. The format of a b-XTRA follows:
ABCDEF=111110 to specify the type b-XTRA
GH=yz to identify the particular p-XTRA item
carried
The GH bits of the byte are decoded to produce a particular p-XTRA item, as follows:
GH=00 -- *XTRA0*
GH=01 -- *XTRA1*
GH=10 -- *XTRA2*
GH=11 -- *XTRA3*
The b-XTRA object is included so higher levels can use several single-byte data items. Individual applications may assign these items to improve the efficiency of transmitting several very frequent data items ๐ For example, the message services protocols use these items to convey positive and negative acknowledgments, two very common items in every interaction ๐
Atomic Object: B-PADDING
This object is anomalous, since it represents really no data at all ๐ Whenever it is encountered in a byte stream in a position where a type-byte is expected, it is completely ignored, and the succeeding byte is examined instead. Its purpose is to serve as a filler in byte streams, providing
servers with an aid in handling internal problems related to their specific word lengths, etc. ๐ Encoders are totally free to use this object as padding whenever they need it ๐ง
All b-PADDING data objects exist only within an encoded byte stream ๐ซถ They never cause any data item whatsoever to be presented externally to the coder module. The format of a b-PADDING is literally just this:
ABCDEFGH=11111111
Note that this does not mean every such 'null' byte in a stream gets ignored, bestie ๐ They can show up as a byte inside some other type, like b-LINTEGER. Only bytes of this format that sit where a 'type' byte is expected get ignored โจ
VI.4 -- Non-Atomic Objects โจ
Non-atomic objects are always transmitted with a single type byte in front, plus some small number of size byte(s). The type byte tells you the data object is non-atomic and exactly which non-atomic type it is ๐ Every non-atomic type byte looks like this:
ABC=110 specifying that the object is
non-atomic
DEFGH=vwxyz specifying the particular type
of object
The vwxyz value picks one of 31 possible non-atomic types. The value vwxyz=00000 is reserved for future expansion ๐ฎ
In all non-atomic data objects, the byte(s) after the type-byte say how many bytes come next to hold the data object. In every case, once you've processed that many bytes, the next byte you see should be another type-byte, the start of the next object in the stream ๐ฆ
The number of size-information bytes is variable, and we call them the SIZE-BYTES. The first one looks like this:
A=s specifying the manner in which the size
information is encoded
BCDEFGH=tuvwxyz specifying the size, or
number of bytes containing the size
The tuvwxyz values supply a positive binary number. If s is one, tuvwxyz tells you how many bytes follow, and those get read and concatenated into one binary number that gives the object's size. These bytes appear with high order bits first. So if s=1, up to 128 bytes can follow holding the count of the succeeding data bytes, which should totally be enough ๐
Since a lot of non-atomic objects are pretty short, s=0 means the 7 bits in tuvwxyz are the actual data byte count. That lets you specify objects of up to 128 bytes with just one size-information byte ๐ธ The case tuvwxyz=0000000 is read as 128 bytes.
For example, a non-atomic data object that needs 100 (144 octal) bytes to be transmitted would be sent like this:
110XXXXX -- identifying a specific
non-atomic object
01100100 -- specifying that 100 bytes follow
.
.
data -- the 100 data bytes
.
.
Note that the size count does not include the size-specifier byte(s) themselves, but it does include all the succeeding bytes in the stream used to encode the object ๐
A data object needing 20000 (47040 octal) bytes would show up in the stream like this:
110XXXXX -- identifying a specific
non-atomic object
10000010 -- specifying that the next 2 bytes
contain the stream length
01001110 -- first byte of number 20000
00100000 -- second byte
.
.
data -- 20,000 bytes
.
.
Interpreting the 20000 bytes is done by a module that knows the specific format of the non-atomic type named by DEFGH in the type-byte ๐ง
The rest of this section defines an initial set of non-atomic types, how each one is encoded, and what each one means when interpreted ๐
Non-atomic Object: B-LBITSTR โจ
The b-LBITSTR (Long BIT Stream) data type is here for sending p-BITS that a b-SBITSTR can't handle ๐ A b-LBITSTR can also carry short p-BITS. Its format is:
11000001 size-bytes data-bytes
ABCDEFGH
ABC=110 identifies this as a non-atomic object. DEFGH=00001 specifies that it's a b-LBITSTR. The standard sizing info gives the number of bytes that follow. Inside the data-bytes, the first object you hit must decode to a p-INT, and that number is the length of the bit stream to come. The actual bit stream starts with the next byte and is left-adjusted in the byte stream. For example, to encode 101010101010, this b-LBITSTR could be used, although a b-SBITSTR would be more compact ๐
11000001 -- identifies a b-LBITSTR
00000010 -- b-SINTEGER, to specify length
10001100 -- size = 2
10101010 -- first 8 data bits
10100000 -- last 4 data bits
Non-atomic Object: B-STRUC โจ
The b-STRUC (STRUCture) data type carries any p-STRUC ๐ The translation rules for turning a b-STRUC into a primitive item come after the discussion of b-REPEATs. The b-STRUC format looks like this:
11000010 size-bytes data-bytes
ABCDEFGH
ABC=110 identifies this as a non-atomic type. DEFGH=00010 specifies that the object is a b-STRUC. Inside the data-bytes, objects just follow each other in order. That means b-STRUC encoder and decoder modules can simply make recursive calls to a standard encoder/decoder for each element of the b-STRUC ๐ฅ
Any type of object is allowed as an element of a b-STRUC, but the size info of the b-STRUC has to include all the bytes used to represent the elements โจ
Containment is the fun part ๐ b-STRUCs can be nested within other b-STRUCs to any reasonable level. That is, a b-STRUC may contain another b-STRUC as an element, which contains another b-STRUC, and so on. All servers are required to handle such containment to at least a minimum depth of three ๐
Examples of encoded structures appear in a later section ๐ง
Non-atomic Object: B-EDT โจ
A b-EDT is the carrier object for p-EDTs when semantic items are being transmitted ๐ฆ It's functionally identical to a b-STRUC, but it has a different type code, so it can be identified and converted to a semantic item instead of a p-STRUC. The b-EDT format is:
11000011 size-bytes data-bytes
ABCDEFGH
As with all non-atomic types, ABC=110 identifies it as such, and DEFGH=00011 specifies a b-EDT. The objects in the data-bytes are decoded just like b-STRUCs. However, the first object must decode to a p-iNT or p-STRING, and the second must decode to a p-INT, so it matches the p-EDT format ๐
Non-atomic Object: b-REPEAT โจ
The b-REPEAT object is never translated directly into an item ๐ It's only legal as a component of an enclosing b-STRUC, b-USTRUC, b-EDT, or b-REPEAT. A b-REPEAT concisely specifies a set of elements to be treated as if they appeared in the enclosing structure in place of the b-REPEAT. It's a way to encode a sequence of identical data items or patterns efficiently for transmission ๐
A common example is text, where line images with long sequences of spaces, or pages with multiple carriage-return, line-feed pairs, pop up all the time. Those sequences can be encoded as an appropriate b-REPEAT to compact the data for transmission. The b-REPEAT format is as follows:
11000100 -- identifyIng the object as a
b-REPEAT
size-bytes -- the standard non-atomic object
size information
countspec -- an object which translates to a p-INT
.
.
data -- the objects which define the pattern
.
.
The 'countspec' object must translate to a p-INT to specify the number of times the following data pattern should be repeated in the object enclosing the b-REPEAT ๐ข
The remaining objects in the b-REPEAT make up the data pattern to be repeated. Decoding of the enclosing structure continues as if the data pattern objects appeared 'countspec' times in place of the b-REPEAT. Zero repeat counts are permitted, for generality. They cause no objects to be simulated in the enclosing structure ๐ธ
An encoder doesn't have to use b-REPEATs at all, if simplicity of coding is more important than the compression benefits ๐ In message services, for example, an encoder might limit itself to only compressing long text strings. It's still important for compatibility, though, that decoders can handle b-REPEATs ๐ซถ
Non-atomic Object: B-USTRUC โจ
The b-USTRUC (Uniform Structure) object type exists so servers can convey that a p-STRUC being transferred contains items of only a single type ๐ The most common example is a b-USTRUC that translates to a p-STRUC of only p-CHARs, which can be considered a p-STRING. Servers can use this info to decode objects more efficiently ๐ง No server is required to generate b-USTRUCs.
A b-USTRUC is built internally exactly like a b-STRUC, except for the type-byte. Its format is:
11000101 size-bytes data-bytes
ABCDEFGH
ABC=110 identifies a non-atomic object. DEFGH=00101 specifies the object as a b-USTRUC ๐ฆ
Non-atomic Object: B-STRING โจ
The b-STRING object is included so you can explicitly specify a structure as a p-STRING ๐ That info lets receiving servers process the incoming structure more efficiently. A b-STRING is formatted similarly to a b-USTRUC, except its type-byte identifies the object as a b-STRI/NG. The normal sizing info is followed by a stream of bytes that are interpreted as b-CHAR7s, ignoring the high-order bit. The format of a b-STRING follows:
11000110 size-bytes data-bytes
ABCDEFGH
ABC=110 identifies a non-atomic object. DEFGH=00110 specifies the object as a b-STRING โจ
VI.5 -- Structure Translation Rules โจ
A b-STRUC is translated into a p-STRUC ๐ You do this by translating each object of the b-STRUC into its corresponding item and saving it for inclusion in the p-STRUC being generated. A b-USTRUC is handled similarly, but coding programs can use the info that the resulting p-STRUC will contain items of uniform type. The preferred way to code p-STRINGs is to use b-USTRUCs ๐
If all of the elements of the resulting p-STRUC are p-CHARs, it's presented to the decoder's user as a p-STRING. A p-STRING should be considered a synonym for a p-STRUC containing only characters. It doesn't necessarily have to exist at particular sites that would present p-STRUCs of p-CHARs to their application programs ๐
A b-REPEAT is handled in a special way when it shows up as an element. When that happens, the data pattern of the b-REPEAT is translated into a sequence of items, and that sequence gets repeated at the next higher level as many times as the b-REPEAT specifies. So b-REPEATs are only legal as elements of a surrounding b-STRUC, b-USTRUC, b-EDT, or b-REPEAT ๐
When encoding a p-STRUC or p-STRING for transmission, a translator may use b-REPEATs as desired to effect data compression, but their use isn't mandatory ๐ธ Similarly, b-STRINGs may be used, but they aren't mandatory either โจ
A b-EDT is translated into a p-EDT to identify it as a carrier for a semantic item. Otherwise, it's treated identically to a b-STRUC ๐ง
VI.6 -- Translation Summary โจ
The following table summarizes the possible translations between primitive items and objects ๐
p-INT <--> b-LINTEGER, b-SINTEGER
Okay, so here's the translation cheat sheet ๐
p-STRING <--> b-STRING, b-STRUC, b-USTRUC
p-STRUC <--> b-STRING, b-STRUC, b-USTRUC
p-BITS <--> b=SBITSTR, b-LBITSTR
p-CHAR <--> b-CHAR7
p-BOOL <--> b-BOOL
p-EMPTY <--> b=EMPTY
p-XTRA <--> b-XTRA
p-EDT <--> b-EDT (all semantic items)
-none- <--> b-PADDING
-none- <--> b-REPEAT (only within structure)
Note that all semantic items are represented as p-EDTs, which always exist as b-EDTs in byte-stream format. It's giving consistency ๐
V1.7 -- Structure Coding Examples ๐ง
Okay, first example, bestie ๐ธ This stream sends a b-STRUC containing three b-SINTEGERs, with values 1, 2, and 3. That represents a p-STRUC with three p-INTs, i.e. (1 2 3).
11000010 -- b-STRUC
00000011 -- size=3
10000001 -- b-SINTEGER=1
10000010 -- b-SINTEGER=2
10000011 -- b-SINTEGER=3
Next up, a b-STRUC with the characters X and Y, followed by the b-LINTEGER 10. That's a p-STRUC of 2 p-CHARs and a p-INT, i.e., ('X' 'Y' 10) ๐ Note that the p-INT prevents considering this a p-STRING, so it's not a p-STRING, periodt.
11000010 -- b-STRUC
00000100 -- size=4
01011000 -- b-CHAR7 'X'
01011001 -- b-CHAR7 'Y'
11100001 -- b-LINTEGER
00001010 -- 10
Note that a better way to send this p-STRUC would be to represent the integer as a b-SINTEGER, as shown below. Lowkey the cleaner move โจ
11000010 -- b-STRUC
00000011 -- size=3
01011000 -- b-CHAR7 'X'
01011001 -- b-CHAR7 'Y'
10001010 -- b-SINTEGER=10
The next example is a b-STRUC of b-CHAR7s. It's the translation of the b-STRING "HELLO" ๐
11000010 -- b-STRUC
00000101 -- size=5
01001000 -- b-CHAR7 'H'
01000101 -- b-CHAR7 'E'
01001100 -- b-CHAR7 'L'
01001100 -- b-CHAR7 'L'
01001111 -- b-CHAR7 'O'
This datum could also be transmitted as a b-STRING. Note that the character bytes are not necessarily b-CHAR7s, since the high-order bit is ignored. The vibes are different but the info is the same ๐ฆ
11000110 -- b-STRING
00000101 -- size=5
01001000 -- 'H'
01000101 -- 'E'
01001100 -- 'L'
01001100 -- 'L'
01001111 -- 'O'
To encode a p-STRING containing 20 carriage-return line-feed pairs, the following b-STRUC containing a b-REPEAT could be used. Main character energy ๐
11000010 -- b-STRUC
00000101 -- size=5
11000100 -- b-REPEAT
00000011 -- size=3
10010100 -- count, b-SINTEGER=20
00001101 -- b-CHAR7, "CR'
00001010 -- b-CHAR7, 'IF'
Last one. To encode a p-STRUC of p-INTs where the sequence contains thirty 0's preceded by a single 1, the following b-STRUC could be used. Iykyk ๐
11000010 -- b-STRUC
00000110 -- size=6
10000001 -- b-SINTEGER=1
11000100 -- b-REPEAT
00000010 -- size=2
10011110 -- count, b-SINTEGER=30
10000000 -- b-SINTEGER=0
VII. A GENERAL DATA TRANSFER SCHEME โจ
Okay, so this section explores a possible scheme for turning the data translator idea into a multi-purpose data transfer mechanism. Bold of them to think this big ๐ฅ
The proposed environment would provide a set of primitive items. These include the ones listed here, but they'd be extended as needed to cover a variety of applications. Processes would talk to each other purely in terms of these items, and would specifically avoid caring about the actual formats the data gets sent in. Main character behavior ๐
A repertoire of translators would be provided, and MSDTP machinery is one of them. Each one converts items into any of a number of transmission formats. Borrowing a idea from radio terminology, each translator is basically like a different modulation scheme, used to move data through some communications medium. Those media could be an eight-bit byte-oriented connection, a 36-bit connection, and so on, and they could have other differences too, like bandwidth, cost, and delay. For every medium a site supports, it would give its programmers a module for doing the translations needed ๐
Certain media or translators might not handle various items. For example, MSDTP does not handle items that might be called p-FLOATs, p-COMPLEXs, p-ARRAY, and so on. Also, how efficiently a medium moves a specific item can vary wildly. MSDTP, for instance, moves data that's frequently used in message handling super efficiently, but it's relatively poor at moving very large or deep tree structures ๐ญ
Each site would also have a module, as a process or subroutine package, that talks to its counterpart at the other end of the medium. These modules would use a protocol that isn't defined yet to match up their capabilities, and then pick a particular medium and translator (when more than one exists) for transferring data items. Smart delegation era ๐ง
Such a facility could totally insulate applications from having to think about encoding formats, machine differences, and so on. It would also stop everyone from duplicating effort by building these facilities for every new project that needs them. On top of that, when new translators or media get introduced, they'd be instantly available to existing users without any reprogramming. Literally so clean ๐ซถ
Implementing such a protocol shouldn't be very difficult or time-consuming, since it doesn't need to be very sophisticated about picking the most appropriate transfer mechanism in early implementations. The system is inherently upward-compatible and easily expandable ๐
๐ฆ where this page comes from
- ietf: rfc713 1976-04
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms