RFC 3018
Unified Memory Space Protocol Specification
Unified Memory Space Protocol Specification ๐ฆ
Okay bestie, let's get into RFC 3018 ๐ It's Experimental (Category: Experimental), written by A. Bogdanov from NKO "ORS" and dated December 2000 ๐ธ It's part of the Network Working Group. The title block doesn't have any Obsoletes or Updates line, so this doc isn't replacing or patching anything ๐
Status of This Memo
This memo defines an Experimental Protocol for the Internet community โจ It is not an Internet standard of any kind ๐ The authors are asking for discussion and suggestions for how to improve it ๐ฌ Distribution of this memo is unlimited ๐
Copyright Notice
Copyright (C) The Internet Society (2000). All Rights Reserved. ๐
Abstract
This document specifies the Unified Memory Space Protocol (UMSP), which gives you the power of immediate access to memory on remote nodes ๐ฅ
Conventions used in this document
Okay so the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are read as described in RFC-2119 [2] ๐ง
The syntax specification below is written in augmented Backus-Naur Form (ABNF), as described in RFC-2234 [3] ๐
Table of Contents
1. Introduction...................................................4
2. The UMSP Model.................................................5
2.1 128-bit Address Space.......................................5
2.2 Computing Model.............................................7
2.3 System Architecture.........................................9
3. Instruction Format............................................11
3.1 Instruction Header.........................................12
3.2 Extension Headers..........................................15
3.3 Instruction Operands.......................................17
3.4 Address Formats............................................17
4. Response of the Instructions..................................19
4.1 RSP, RSP_P.................................................20
4.2 SND_CANCEL.................................................20
5. Jobs Management...............................................21
5.1 Job Initiate...............................................23
5.1.1 CONTROL_REQ............................................24
5.1.2 CONTROL_CONFIRM........................................25
5.1.3 CONTROL_REJECT.........................................26
5.2 Task Initiate..............................................26
5.2.1 TASK_REG...............................................26
5.2.2 TASK_CONFIRM...........................................27
5.2.3 TASK_REJECT............................................28
5.2.4 TASK_CHK...............................................28
5.3 Establishment of session connection........................29
5.3.1 SESSION_OPEN...........................................29
5.3.2 SESSION_ACCEPT.........................................31
5.3.3 SESSION_REJECT.........................................31
5.3.4 Connection Profile.....................................32
5.4 Session Closing............................................33
5.4.1 SESSION_CLOSE..........................................34
5.4.2 SESSION_ABEND..........................................35
5.5 Task Termination...........................................35
5.5.1 TASK_TERMINATE.........................................36
5.5.2 TASK_TERMINATE_INFO....................................36
5.6 Job Completion.............................................37
5.6.1 JOB_COMPLETED..........................................37
5.6.2 JOB_COMPLETED_INFO.....................................38
5.7 Activity Control of Nodes..................................38
5.7.1 _INACTION_TIME.........................................39
5.7.2 STATE_REQ..............................................40
5.7.3 TASK_STATE.............................................41
5.7.4 NODE_RELOAD............................................42
5.8 Work without session connection............................42
6. Instructions of Exchange between VM...........................44
6.1 Data Reading/Writing Instructions..........................45
6.1.1 REQ_DATA...............................................45
6.1.2 DATA...................................................46
6.1.3 WRITE..................................................46
6.1.4 WRITE_EXT..............................................47
6.2 Comparison Instructions....................................47
6.2.1 CMP....................................................47
6.2.2 CMP_EXT................................................48
6.2.3 Response to Comparison Instructions....................48
6.3 Control Transfer Instructions..............................48
6.3.1 JUMP, CALL.............................................48
6.3.2 RETURN.................................................49
6.4 Memory Control Instructions................................50
6.4.1 MEM_ALLOC..............................................50
6.4.2 MVCODE.................................................50
6.4.3 ADDRESS................................................51
6.4.4 FREE...................................................51
6.4.5 MVRUN..................................................51
6.5 Other Instructions.........................................52
6.5.1 SYN....................................................52
6.5.2 NOP....................................................53
6.6 Work with Objects..........................................53
6.6.1 Reading/Writing of the Objects Data....................54
6.6.1.1 OBJ_REQ_DATA.......................................54
6.6.1.2 OBJ_WRITE..........................................55
6.6.1.3 OBJ_WRITE_EXT......................................56
6.6.2 Comparison Instructions of the Objects Data............56
6.6.2.1 OBJ_DATA_CMP.......................................56
6.6.2.2 OBJ_DATA_CMP_EXT...................................57
6.6.3 Execution of the Objects Procedures....................57
6.6.3.1 CALL_BNUM..........................................57
6.6.3.2 CALL_BNAME.........................................58
6.6.3.3 GET_NUM_PROC.......................................59
6.6.3.4 PROC_NUM...........................................59
6.6.4 The Objects Creation...................................59
6.6.4.1 NEW, SYS_NEW.......................................60
6.6.4.2 OBJECT.............................................61
6.6.4.3 DELETE.............................................61
6.6.5 The Objects Identification.............................61
6.6.5.1 OBJ_SEEK...........................................62
6.6.5.2 OBJ_GET_NAME.......................................62
7. Chains........................................................62
7.1 Sequence...................................................63
7.2 Transaction................................................64
7.2.1 _BEGIN_TR..............................................64
7.2.2 EXEC_TR................................................65
7.2.3 CANCEL_TR..............................................66
7.3 Fragmented instruction.....................................66
7.4 Buffering..................................................67
7.5 Acknowledgement of chains..................................69
7.6 Base-displacement Addressing...............................70
8. Extension Headers.............................................71
8.1 _ALIGNMENT.................................................71
8.2 _MSG.......................................................71
8.3 _NAME......................................................72
8.4 _DATA......................................................72
8.5 _LIFE_TIME.................................................72
9. Search of resources...........................................73
9.1 VM_REQ.....................................................75
9.2 VM_NOTIF...................................................75
10. Security Consideration.......................................77
11. Used Abbreviations...........................................78
12. References...................................................79
13. Author's Address.............................................80
14. Full Copyright Statement.....................................81
1. Introduction โจ
UMSP is a network connection-oriented protocol ๐ It lines up with the session and presentation layers of the OSI model ๐ It's designed to fit a huge range of systems, from simple devices built on dedicated processors all the way up to universal computers and clusters ๐ธ
For moving data, the protocol uses a transport layer service with reliable delivery ๐ซถ It's also possible to use a protocol that doesn't provide reliable delivery, but only for data that doesn't require acknowledgement ๐ This document describes using TCP and UDP ๐
The basic purpose of UMSP is to create a network environment that organizes a 128-bit address space of memory distributed across Internet nodes ๐ The protocol defines the connection management algorithm and the format of network primitives ๐ It doesn't control local memory on the node ๐
Here's the main character energy ๐ญ In traditional network protocols, user applications swap network primitives or work with dataflows. With UMSP, applications on different nodes interact by reading or writing data immediately, or by transferring control to code in the virtual memory of a remote node โจ The user's application doesn't have to know the protocol or network even exists. It just uses instructions with 128-bit addresses ๐ฆ iconic, honestly
Firstly, UMSP is meant for systems based on virtual machines (VM) that execute pseudo-code ๐ง However, the protocol may also be used in systems that execute processor code, for example in clusters or universal operating systems, to organize a distributed virtual address space ๐ Besides that, the minimal profile of the protocol may be used in simple devices that don't have an operating system ๐ธ
The protocol gives various ways to set connection parameters, and it allows building systems with a high protection level without restricting application functionality ๐ฅ
UMSP can seriously simplify the distributed systems development process ๐ซถ It lets you unite not only information but also the computing resources of a large number of polytypic computers, without big expenses for program standardization and development ๐ ๐
2. The UMSP Model ๐
2.1. 128-bit Address Space โจ
okay so UMSP runs on a 128-bit distributed address memory space model ๐ฆ. One 128-bit address packs in the network type, the network node address, and the local memory address all together. It looks like this:
Octets
0 1 16
+------+--------------+--------------------+----------------+
|Header| FREE | NODE_ADDR | MEM_ADDR |
+------+--------------+--------------------+----------------+
The full address length is fixed at 16 octets, every time ๐
Header ๐
1 octet. The address header field completely defines the address format. Here's how the header is laid out:
Bits
0 1 2 3 4 5 6 7
+-----+-----+-----+-----+-----+-----+-----+-----+
| ADDR_LENGTH | NET_TYPE | ADDR_CODE |
+-----+-----+-----+-----+-----+-----+-----+-----+
ADDR_LENGTH (4 bits): the length of the network address. This is the number of octets in the NODE_ADDR field. The value 0 is not allowed, so don't even try ๐
NET_TYPE (2 bits): the network type. It says what kind of network the node is sitting in.
ADDR_CODE (2 bits): the length code of the local memory address. The value here tells you how long the MEM_ADDR field is. These are the values and their matching MEM_ADDR lengths:
%b00 - 16 bit
%b01 - 24 bit
%b10 - 32 bit
%b11 - 64 bit
So when you combine the three header fields, you get what's called an address format number ๐ธ. Those three values together uniquely pin down the network the node lives in. The format number is written like this:
N <ADDR_LENGTH> - <NET_TYPE> - <ADDR_CODE>
Here's an example. N 4-0-2 means the node network address is 4 octets long and the memory address is 32 bits. Network type 0 is the one reserved for IPv4 in this document, so that's the vibe for this format ๐. If the network type is 0, you can leave it out when writing the format number. That's why N 4-0-2 and 4-2 mean the exact same thing. And if both NET_TYPE and ADDR_CODE are 0, you can drop both. This is how a format number ends up as a single figure, which is honestly so clean โจ
One or several address format numbers must be assigned for each global network that's part of the unified system. No skipping this part, bestie!
FREE ๐ง
0 to 12 octets. This field is unused by the protocol. It can hold any extra info the node's memory control system needs. If you're not using it, every octet has to be set to zero. Also, if you use this field, the network instructions must carry the complete 16-octet address, and you can't use the short local memory address anymore. Big trade-off, iykyk ๐
NODE_ADDR ๐
1 to 13 octets. This is the node address. How this field is formatted is defined separately for each address format number. The node address should not necessarily precisely correspond to the real network address. If the real network address is longer than this field, you need to set up a subset of addresses in the network that supports UMSP addresses. Think of it as a little translation squad ๐
MEM_ADDR ๐
16, 24, 32, or 64 bits. This is the address of local memory. It's the memory address inside the system that NODE_ADDR points to. The node is totally in charge of its own memory control. The protocol doesn't define the order of use or the format of this field, so the node gets to decide that one ๐ซถ
The 128-bit address is one single field for user applications, so user code has no idea how the addressed memory is physically arranged. Super mysterious, super iconic ๐ฅ
The 128-bit memory address can get sent between nodes as data. For example, it might travel in a buffer of function parameters, or inside an instruction that copies data. So it has to identify the given node uniquely, separate from every other node. No mix-ups allowed ๐
There isn't any fixed algorithm that connects a real network to a 128-bit address. All the address formats in use must be known beforehand, periodt.
Since UMSP has its own address space, it can unite several global networks. Nodes can also have internal local networks, or subordinate addressable devices connected to the node through non-network communications. For any node, given an address format number, there must be a way to find the gateway that responds for routing that address. Main character routing energy ๐ฆ
2.2. Computing Model ๐ธ
The computing model has three layers:
- Job
- Task
- Thread of control
The job is the user application. The job is distributed, so it can run on many nodes at the same time. Control of the job is centralized, and it's handled from a node called the Job Control Point (JCP). One JCP can control a few jobs. The JCP can sit on the same node where the job was created, or on any other addressable network point.
The task is how the job shows up on one separate node. A task can have one or more computing threads of control. A job gets only one task on each node, so no doubling up ๐
The job finishes when its user application finishes. And when the job ends, all of its tasks on all nodes are finished too ๐
The job gets its own isolated 128-bit address space. That space is segmented, and each segment is the local memory of one node. The protocol also lets you work with objects, and an object is a separate associative memory of a node. Lowkey a whole mini ecosystem ๐ง
The task thread is the actual control thread that runs on a specific node, executed by the VM there. A thread can read and write to any address inside the job's 128-bit address space. If control jumps to an address on another (remote) node, a new thread gets created on that remote node. A continuous code segment can't be spread across several nodes, and you also can't get a continuous memory area that's spread across several nodes. Hard no ๐
The protocol doesn't require support for different tasks that use memory spaces which don't overlap, coming from a separate VM node. Multi-thread support isn't a required feature either ๐ฆ
The 128-bit Global Job Identifier (GJID) is defined by the protocol. It gets assigned by the JCP that's going to control the job. At every moment in time, all active GJIDs have unique values across the whole unified system. Unique ID energy, no cap โจ
A job can hold VM code of different types. Those different VM types can live on one node or on different nodes. There's a mechanism for grouping different VM types together on one node, which lets non-uniform code run on a single node inside the same job context. The groups are explained in more detail in section 9 ๐. VM parts that are part of a group must work in a common memory space, meaning they share a common memory control subsystem ๐
2.3. System Architecture โจ
okay bestie, let's look at how the whole setup is structured ๐ง The system is built around Virtual Machines, and the picture is right here:
Node 1 Node 2
-------- --------
+--------------------+ +--------------------+
| User Application 1 | | User Application 1 |
+-----------------------+ +-----------------------+
| User Application N | | User Application N |
+--------------------+ +--------------------+
+-----+ +-----+ +-----+ +-----+ +-----+ +-----+
| VM1 | | VM2 | . . . | VMn | | VM1 | | VM2 | . . . | VMn |
+--+--+ +--+--+ +--+--+ +--+--+ +--+--+ +--+--+
| | | | | |
+--------------------------+ +--------------------------+
| | | |
| +-----+ U M S P | | U M S P |
| | JCP | | | |
| +-----+ | +-------------+------------+
+-------------+------------+ |
| +-----+-----+
+-----+-----+ | TCP |
| TCP | +-----+-----+
+-----+-----+ |
| |
+-----------------/ |
/------------------+
/
|
+-----+-----+
Node N | TCP |
-------- +-----+-----+
|
+------------+------------+
| +-----+ |
| | JCP | U M S P |
| +-----+ |
+-------------------------+
Figure 1. Structure of the system based on use VM.
okay so one or several VMs sit on the upper level for UMSP ๐ The VM layer is not the network level. The last network level is UMSP, so the VM layer has no network primitives of its own and uses the same field of operation code together with UMSP ๐ซถ
The end user of the protocol is the user code, which runs inside the virtual machine. That code has instructions with the 128-bit address. The VM translates these instructions into network commands, and those commands go through UMSP to be executed by the remote machine ๐ฆ How the VM is organized internally, its command system, and its API can be anything. The protocol only defines the format of the primitives that the virtual machines swap across the network โจ
The protocol does not control the job's memory ๐ controlling memory is the VM's job. If a few VMs run on one node, they can share a common memory space, or they can be completely isolated from each other ๐ธ
UMSP uses a transport layer with reliable delivery for data exchange. This document defines the use of TCP ๐ For transfers that don't need acknowledgement, UDP may be used. So a TCP connection is obligatory, and multiple TCP connections with multiplexing are supposed. Controlling transport connections is not part of the UMSP protocol ๐
The UMSP instructions don't contain the network addresses of the receiver and sender. The protocol requires that one UMSP address corresponds to exactly one transport layer address. That means the node address on the transport layer has to be unambiguously defined by the 128-bit memory address ๐
Other transport protocols, or even no network communication at all, can be used instead of TCP. They have to meet these requirements:
- Reliable delivery. The transport layer must inform about delivery or its impossibility;
- The violation of a sequence of transmitted segments is allowed;
- The duplication of segments is not allowed;
- At emergency reload of nodes it is necessary to guarantee identification of segments concerning session connections, assigned up to reload;
- Use connectionless-mode is possible.
VM is an independent program. It only needs to interact with the protocol when it executes instructions with the 128-bit address that concern another node ๐ง A VM can run several user tasks, and each task can contain several threads of control. The VM must be able to interpret application instructions with the 128-bit address into one or several UMSP protocol instructions ๐
Session connections open between nodes for data exchange. One connection relates to only one job, but several session connections for different jobs can run at the same time between two nodes. The protocol also provides connectionless data exchange โจ
The exchange between UMSP nodes can include these types of instructions:
- Immediate reading/write in memory;
- Requests of allocation/free memory;
- Comparison instructions;
- Call-subroutine and unconditional jump instructions;
- Synchronization instructions;
- Work with objects instructions - reading / writing in memory of objects and execution of objects procedures.
UMSP does not track the user's control threads. The VM has to provide the necessary order of performance for the instructions itself ๐
The length of UMSP instructions doesn't depend on the segment length of the transport layer. Segmentation is provided for transferring long instructions. Short instructions can be packed into one segment, with the option of compressing headings used for that transfer ๐ The minimum size of a segment needed to work is 6 octets. To realize all functions, 54 octets are necessary ๐ฅ
3. Instruction Format ๐
okay the UMSP instruction is made of a basic header, extension headers, and operands ๐ All fields have variable length ๐ฆ
+----------------+----------------------+------------------------+
| Header | Extension headers | Operands |
+----------------+----------------------+------------------------+
The header holds the operation code and the information needed to interpret the instruction โจ The optional extension headers hold extra information that isn't defined in the basic header ๐ The operands hold the instruction's data ๐
The instruction format lets you calculate the common instruction length without knowing the definition of each separate operation code, which is lowkey genius ๐ง โจ The instruction headers come in short and extended formats, so the protocol keeps working well across a wide range of network speeds ๐ There's also a simple algorithm for compressing the headers, so it's giving efficiency ๐ซถ
All instructions and extension headers have identifiers, written in upper case letters ๐ธ Instruction identifiers begin with a letter, and extension header identifiers begin with an underscore symbol ๐
3.1. Instruction Header โจ
okay so the header is where the whole instruction starts, and it's giving very structured ๐ here's the layout bestie:
Octets:
+0 +1
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
0: | OPCODE |ASK| PCK |CHN|EXT| OPR_LENGTH|
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2: | OPR_LENGTH_EXT |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
4: | CHAIN_NUMBER |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
6: | INSTR_NUMBER |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
8: | |
+ SESSION_ID +
| |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
12:| |
+ REQ_ID +
| |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
OPCODE ๐ฅ
it's 1 octet, the operation code ๐ฆ what its value means depends on the instruction. the codes are split into these intervals:
1 - 112 management instructions
113 - 127 reserved
128 - 223 instructions of exchange between VM
0, 224, 255 reserved
ASK ๐
1 bit, and it's the flag of response necessity ๐ซถ it decides whether the field REQ_ID is in the header. if ASK = 1, there is a REQ_ID field in the instruction. if EXT = 0, the REQ_ID field in the instruction is absent. (yes, the text says EXT there, not ASK. it's giving a typo, but we keep it as written ๐)
PCK ๐ง
2 bits, the header compression attribute. these bits pack instruction headers sent on one TCP connection, or let several instructions ride in one UDP package. it all rests on the assumption that two instructions in a row very probably belong to the same session connection, or the same chain ๐ the PCK values are:
%b00: the instruction does not belong to a definite session. the CHAIN_NUMBER, INSTR_NUMBER and SESSION_ID fields are absent from its header.%b01: the instruction concerns the same session connection as the previous one. the SESSION_ID field is absent from its header.%b10: the instruction belongs to the same connection and the same chain as the previous one. the CHAIN_NUMBER, INSTR_NUMBER and SESSION_ID fields are absent from its header. the INSTR_NUMBER value of the current instruction is calculated by adding one to the INSTR_NUMBER value of the previous instruction.%b11: the instruction may or may not concern the same session as the previous one. the SESSION_ID field is present. whether CHAIN_NUMBER and INSTR_NUMBER are present is decided by the CHN flag.
CHN โ๏ธ
1 bit, the chain flag ๐ธ instructions about one job, sent on one session connection, can be unified into a chain. chains get a proper deep dive in section 7. the original says If SEQ = 1 here, which we're keeping word for word ๐ซ when the instruction is connected to a chain, the CHAIN_NUMBER and INSTR_NUMBER fields are there (INSTR_NUMBER only if PCK is not set to %b10). when CHN = 0, the instruction isn't connected to a chain, so those two fields are not in it.
EXT ๐
1 bit, the flag for whether extension headers are present. if EXT = 1, there's one or more extension headers in the instruction. if EXT = 0, there aren't any.
OPR_LENGTH ๐
3 bits, the number of 32 bit words in the operands field. the value 0 means there's no operands field at all. the value %b111 switches on the extended header format, and in that format the length of operands comes from OPR_LENGTH_EXT instead, so OPR_LENGTH isn't used.
OPR_LENGTH_EXT ๐
2 octets, the number of 32 bit words in the operands field. this field is only in the header if OPR_LENGTH = %b111. if OPR_LENGTH < > %b111, the OPR_LENGTH_EXT field is absent. if OPR_LENGTH_EXT = 0, the operands field is absent too. you'd use OPR_LENGTH_EXT instead of OPR_LENGTH for these reasons:
- if the operands length has to be more than 24 octets
- if making the fields alignment of 4 octets is more effective than compressing the header by 2 octets
CHAIN_NUMBER ๐
2 octets, the number of the chain this instruction belongs to. the values %x0000 and %xFFFF are reserved, so don't use them, periodt ๐
INSTR_NUMBER ๐ข
2 octets, the serial number of the instruction inside its chain. numbering starts at zero. the value %xFFFF is reserved.
SESSION_ID ๐ชช
4 octets, the identifier of the session connection, assigned by the instruction receiver. when a session connection opens, each side sets its own identifier for the connection and tells the other side what it is ๐ซถ a zero value means the instruction doesn't concern a definite session. the value %xFFFFFFFF is reserved.
REQ_ID ๐จ
4 octets, the request identifier. it's used to match requests up with their responses โจ
Now, the identifier OPR_LENGTH shows up in the instruction format descriptions, and it means "use the OPR_LENGTH_EXT field if OPR_LENGTH = %b111". an instruction whose operands are 24 octets or fewer can go in the short header format (OPR_LENGTH < > %b111) or the extended one (OPR_LENGTH = %b111). both are equivalent, so you pick whichever you like ๐ฆ
the minimal header length is 2 octets in the short format and 4 octets in the extended format. the maximal header length is 16 octets ๐
3.2. Extension Headers ๐งฉ
if the EXT flag in the instruction header is set to 1, the instruction has anywhere from one up to thirty extension headers. extension headers do two jobs:
- sending service information that wasn't provided in the basic header
- sending data longer than 262240 octets in one instruction
the extension headers all share this common format:
Octets:
+0 +1
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
0: |HXT| HEAD_LENGTH | HEAD_LENGTH_EXT |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2: | continued HEAD_LENGTH_EXT |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
4: |HSL|HOB|HRZ| HEAD_CODE | HEAD_CODE_EXT |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
6: | RESERVED |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
8: | |
/ DATA /
/ /
| |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
HXT ๐ช
1 bit, which specifies the length of the data length field. if HXT = 0, the extension header's length is defined by HEAD_LENGTH, and HEAD_LENGTH_EXT is absent. if HXT = 1, the header's length comes from HEAD_LENGTH and HEAD_LENGTH_EXT put together.
HEAD_LENGTH ๐
7 bits, the number of 16 bit words in the DATA field. if HXT = 0, it's an independent field. if HXT = 1, it holds the senior bits of the complete length field.
HEAD_LENGTH_EXT ๐งฎ
3 octets, the number of 16 bit words in the DATA field. if HXT = 0, this field is absent. if HXT = 1, it holds the younger bits of the complete length field.
HSL ๐
1 bit, the flag for the last header. it's set to 1 on the last extension header in the instruction, and set to 0 on all the others.
HOB ๐ซ
1 bit, the flag for obligatory processing. it decides how the instruction gets processed when the receiving node doesn't know what the extension header is for, or can't process it for some reason. if HOB = 1, the instruction must not be carried out. if HOB = 0, it doesn't affect instruction processing. the protocol must process all extension headers, no matter whether errors are present ๐
HRZ ๐ท
1 bit, reserved for future expansions. the protocol must not analyze this field when receiving, and it must be set to 0 when sending.
HEAD_CODE ๐ท๏ธ
5 bits. if HXT = 0, the field holds the extension header code. if HXT = 1, this field joins up with HEAD_CODE_EXT, and it holds the senior bits of the header code.
HEAD_CODE_EXT ๐ช
1 octet. if HXT = 0, this field is absent. if HXT = 1, it holds the younger bits of the header code.
RESERVED ๐ซง
2 octets. if HXT = 0, this field is absent. if HXT = 1, it's reserved for further use. in the current realization of the protocol, the RESERVED field must not be analyzed by the protocol during receiving. it must be set to 0 when sending.
DATA ๐
the data field of the extension header. if HXT = 0, its length is 0 - 254 octets. if HXT = 1, its length is 0 - 4 * 10^9 octets. the format of this field is defined separately for each value of the header code.
on the receiving side, extension headers must be processed in the order they appear in the instruction. if an instruction has more than 30 extension headers, it's considered erroneous, and the session connection it was sent on has to be broken off after that instruction is received ๐จ
the identifiers HEAD_LENGTH and HEAD_CODE get used later on when the extended headers' formats are described. they stand for HEAD_LENGTH + HEAD_LENGTH_EXT and HEAD_CODE + HEAD_CODE_EXT when HXT = 1. headers with codes 0 - 30 can be sent in both the short (HXT = 0) and the extended (HXT = 1) format ๐ธ
3.3. Instruction Operands ๐
the operands field holds the instruction's data ๐ its length is shown in OPR_LENGTH or OPR_LENGTH_EXT, and it's always a multiple of four octets. if needed, 1 - 3 zero-value octets get padded onto the end of the field. the maximal length of operands is 262140 octets. if the instruction needs to carry more data than that, the extension headers come in ๐ง
the format of the operands field is defined separately for each instruction, so check each instruction's own definition for the details ๐ซถ
3.4. Address Formats ๐ธ
okay so the address formats here are lowkey the coolest part ๐ฆ The following address format numbers are definite for nodes that are immediately connected to the global IPv4 network:
N 4-0-0 (4)
N 4-0-1 (4-1)
N 4-0-2 (4-2)
Here are the 128-bit address layouts ๐ Each one is a 16-octet grid, so you can see exactly where each field sits:
Octets:
+0 +1 +2 +3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0: |0 1 0 0|0 0|0 0| Free |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4: | Free |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8: | Free | IP address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12:| IP address | Local memory address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0: |0 1 0 0|0 0|0 1| Free |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4: | Free |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8: | Free | IP address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12:| IP address | Local memory address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
0: |0 1 0 0|0 0|1 0| Free |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4: | Free |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8: | IP address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12:| Local memory address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Here's what each field means โจ
- Free: it is not used by the protocol ๐ซถ
- IP address: it sets the node address in the global IPv4 network ๐
- Local memory address: it is described in section 2.1 ๐
The IP address uniquely (unequivocally) identifies nodes of the given type ๐ TCP is used for talking to these nodes. For sending instructions that don't need a response, using UDP is allowed ๐ฆ IANA has assigned port 2110 for both TCP and UDP. This port must be open for listening (receiving) ๐ A TCP node that is starting the connection opening, or a UDP node that is doing the package sending, can use any port. Using several TCP connections with multiplexing is supposed ๐ง
4. Response of the Instructions ๐
okay this section is all about how responses get matched up ๐ฅน The protocol instructions come in two types:
- The management instructions transmitted on UMSP layer (
OPCODE = 1 - 112). - The instructions of the exchange between VM (
OPCODE = 128 - 223).
The two types get handled differently โจ
- The REQ_ID request identifier field is formed by the protocol for instructions of the first type, and it is formed by VM for instructions of the second type ๐ซถ
- The protocol must analyze the REQ_ID field and compare it with the instructions transmitted earlier, after receiving a response instruction of the first type ๐
- The protocol must not analyze the REQ_ID field after receiving a response instruction of the second type. That instruction is simply sent to VM ๐
Response instructions have the ASK field equal to 1. That means the header has the REQ_ID field. The value taken from the confirmed instruction gets written into the REQ_ID field. A response instruction does not require a response itself ๐ธ
A few VM can be connected to the protocol on the same node, and every VM can work in its own address space. The request identifiers for different VM can coincide, so an instruction gets identified by two fields ๐
- The session identifier SESSION_ID, which is connected with a definite VM.
- The request identifier REQ_ID.
4.1. RSP, RSP_P
"Response" (RSP) and "Response of the protocol" (RSP_P) instructions have the identical format. The only difference is the operation code ๐
OPCODE = 129/1 ; correspondingly to RSP/RSP_P
ASK = 1
PCK = %b01/11
EXT = 0/1
CHN = 0
OPR_LENGTH = 0/1
SESSION_ID and REQ_ID - The values is taken from the confirmed
instruction.
Operands:
2 octets: The basic return code.
2 octets: The additional return code.
The optional extension header:
_MSG - contains the arbitrary error description.
An instruction without operands is used for the positive response. It's equivalent to zero values for the basic and additional return codes ๐
The zero basic return code is used for a positive response, and the additional return code may have a non-zero value ๐
An instruction with a non-zero basic return code is used for a negative response. The basic return code defines the error category, and the additional return code identifies an error ๐ญ
The RSP instruction is formed upon the VM request, and the return codes must be received from VM. If the protocol cannot deliver the instruction that requires a response to VM, it forms a negative RSP response independently ๐
The RSP_P instruction is always formed at the UMSP layer. If the protocol cannot define which instruction the RSP_P is transmitted for, nothing is executed ๐
4.2. SND_CANCEL
Sometimes you need to cancel sending after part of the data has already been transmitted and taken up the buffer on the reception side. This can happen when you're sending long fragmented instructions or transactions ๐ฅบ The protocol gives you the "The sending is canceled" (SND_CANCEL) instruction for exactly this. Its fields look like this ๐
OPCODE = 2
ASK = 0
PCK = %b01/10/11
EXT = 0/1
CHN = 1
OPR_LENGTH = 1
SESSION_ID - The value is taken from the cancelled chain.
CHAIN_NUMBER - Number of the chain, which sending is cancelled.
INSTR_NUMBER - Always has zero-value.
Operands:
2 octets: The basic return code.
2 octets: The additional return code.
The optional extension header:
_MSG - contains the arbitrary error description.
SND_CANCEL is used to cancel a partially transmitted transaction or fragmented instruction. When the receiver gets SND_CANCEL, all the data it had already received in the chain gets rejected ๐งน
5. Jobs Management ๐
okay jobs management is a whole vibe ๐ซ It covers these four functions:
- Initiation and completion of jobs;
- Initiation and completion of tasks;
- Opening and closing of session connections;
- Activity control of nodes.
The instructions with OPCODE = 1 - 112 are used for jobs management. These instructions must be sent through TCP. Using UDP is not allowed, even if the instructions don't demand a response ๐ซ
UMSP is built on a model with centralized control of each separate job ๐ง The reason is that pointer control isn't really possible in a decentralized system. Any task can finish at any moment, or a node can be reloaded. In a decentralized system there's no way to guarantee that all the other nodes the job runs on get notified ๐ฉ Since the job keeps existing, the task for that job can be initiated again on the same node. That task can allocate new dynamic resources, and the addresses of those newly allocated resources can overlap with addresses of resources that existed on the node before the task restarted. Old pointers can survive on other nodes. They might still be formally correct, but they'd actually point at other objects. Uncontrollable application behavior can be the result of that situation ๐ฅ
UMSP handles this with the following approach โจ
- It lets you pinpoint exactly which node the task was completed on.
- If the task on a node finishes before the job ends, all nodes that are executing the job get notified of it.
- Repeated task initialization on a node is allowed, while all nodes will receive the message about the first task's end.
The protocol does not control the pointers. VM supervises pointer correctness ๐ซถ VM must have an architecture in which 128-bit pointers are stored in special memory areas for this purpose. The protocol informs VM about the nodes where a task has finished its work. VM must make all pointers concerning such tasks invalid. This results in exclusive situations when accessing through those pointers. If the application provides processing exceptions, it keeps its capacity for work, or it's finished in an emergency. That decision helps exclude unguided applications from working ๐
โ ๏ธ The key thing here: pointer correctness is VM's job, not the protocol's. If VM doesn't invalidate the pointers for finished tasks, the results can be unpredictable, so don't skip this step.
To solve these questions at the UMSP level, a control job node is defined for each job. It's named the Job Control Point (JCP) ๐ It can be the same node where the job is initiated, or it can be another dedicated node. The basic JCP function is to trace the initialization and the end of the job's tasks. Besides that, the dedicated JCP node may be used for centralized user identification and attack protection ๐ก๏ธ
The following identifiers are defined for jobs and tasks control ๐
- Locally Task Identifier (LTID) is assigned to each active task on the node. LTID's length equals the length of the local memory address defined for the node. All LTIDs on the node must have unique values at every moment in time. It's allowed to reuse an LTID that was used earlier by already completed tasks for newly initiated tasks ๐
- JCP assigns the Control Task Identifier (CTID) to each task of the job. Its length equals the length of the local memory address on the JCP node. All CTIDs on the JCP must have unique values at every moment in time. Unlike LTID, the CTID value is chosen with some restrictions ๐ง
- Globally Task Identifier (GTID) is assigned to each task. GTID has the same format as a 128-bit node memory address. The local memory address part is replaced with the LTID ๐
- Globally Job Identifier (GJID) is assigned to each job. GJID is defined on the JCP node and has the same format as a 128-bit JCP node memory address. The local memory address part is replaced with the CTID of the job's first (initial) task. GJID is used in the session connection opening procedure to define the JCP that controls the job ๐
LTID and CTID are written into instructions in a field of length 2/4/8 octets. If the field allocated for the identifier in the instruction is longer than the identifier, LTID (CTID) gets written in the last octets, and the value 0 must be written in the initial octets. If the received LTID (CTID) is shorter than the local memory address, it's necessary to pad it with zero octets at the beginning ๐งธ
GTID and GJID are written into instructions in a field of length 4-16 octets. The FREE field is not present in these identifiers (see section 2.1). It's considered to contain zero-value octets. The length of the identifier is defined in the address header ๐
So the protocol runs a timeout whenever it sends CONTROL_REQ, TASK_REG or SESSION_OPEN โฐ The node picks that value, and it has to be more than three intervals of the maximal delivery time at the transport layer ๐ Time spent waiting in the queue to the transport layer doesn't count toward it โจ
5.1. Job Initiate ๐
The job is basically the user application running on a VM ๐ป Starting the UMSP job can happen at the same time the application starts, or while it's already running ๐ธ
The task that belongs to the job gets initialized on the node together with the job, and LTID gets bound to that task ๐ง
If the node where the user application was loaded is picked as JCP, then initializing the job is outside the scope of the network protocol ๐ But another node can be chosen as JCP for these reasons:
- The job initialization node is connected to the network by a slow-speed or overloaded channel. Sending managing traffic there is undesirable.
- The node has no computing power for running the managing tables.
- Authentication on the detailed node is necessary.
If another node gets chosen for JCP, the node that initiates the job must register the job at JCP ๐
5.1.1. CONTROL_REQ ๐ฆ
The "To request a control" (CONTROL_REQ) instruction gets sent from the node that's initiating the job over to the JCP of another node ๐ Here's what its fields look like:
OPCODE = 3
PCK = %b00
CHN = 0
ASK = 1
EXT = 0/1
OPR_LENGTH = 2/3 ; Depends on LTID length.
REQ_ID - The value is assigned by the sender node protocol and
then will be sent in the response.
Operands:
4 octets: The control parameters profile. This field has the
following format:
bits
0 1 2 3 4 5 6 7
+-----+-----+-----+-----+-----+-----+-----+-----+
| |
+ JOB_LIFE_TIME +
| |
+-----+-----+-----+-----+-----+-----+-----+-----+
| CMT | Reserved | VERSION |
+-----+-----+-----+-----+-----+-----+-----+-----+
| Reserved |
+-----+-----+-----+-----+-----+-----+-----+-----+
JOB_LIFE_TIME
2 octets. The job lifetime in seconds. The zero-value
signifies that the restriction of the job lifetime is
unused.
CMT
1 bit. The flag of several JCP using. This field is
reserved for the future expansion of the protocol.
VERSION
1 octet. The number of the UMSP version. It must
contain the value 1.
Reserved
3 + 8 bits. All bits must be set to 0.
4/8 octet: LTID of task of the job, assigned on the node, which
initiate the job (by the sender of this
instruction).
The optional extension headers:
_JOB_NAME - This header contains the name of the Job. Is
assigned once and must not change further.
_INACT_TIME - This header contains the inaction time (see
section 5.7).
Quick breakdown of that 4-octet control parameters profile ๐ JOB_LIFE_TIME is 2 octets and holds the job lifetime in seconds, where zero means there's no job lifetime restriction ๐ฐ๏ธ CMT is 1 bit reserved for future protocol expansion, and it's the flag for several JCP using ๐ VERSION is 1 octet and must be 1, since that's the UMSP version number ๐ And the Reserved bits (3 + 8 bits) all have to be set to 0 ๐งธ
When JCP gets a CONTROL_REQ, it checks the LTID value from the instruction and does one of these:
- If the node that sent CONTROL_REQ already has an active job registered on JCP with that same LTID, JCP sends the notification about the abnormal end of the registered job, as described in section 5.5.2 (it's assumed the node was reloaded) ๐ญ After that, the sanction for starting the new job gets sent.
- If the node has no registered job with the received LTID, JCP allows the new job to start right away โ
If JCP confirms the control, it sends the CONTROL_CONFIRM instruction. Otherwise, it sends CONTROL_REJECT ๐
5.1.2. CONTROL_CONFIRM ๐ท
The "To confirm the control" (CONTROL_CONFIRM) instruction is sent from JCP as the positive response to a CONTROL_REQ ๐ฅฐ Its fields look like this:
OPCODE = 4
PCK = %b00
CHN = 0
ASK = 1 ; The instruction does not need to be responded. This flag
specifies presence of the REQ_ID field.
EXT = 0/1
OPR_LENGTH = 1-4 ; Depends of length of the GJID.
REQ_ID - The value is taken from the instruction CONTROL_REQ
Operands:
4-16 octets: The GJID assigned to the job on the JCP.
Sending CONTROL_REQ means two things at once: a request for control and a request for task initiation ๐ซถ The CTID assigned to the task is part of the GJID (it's the field of the local memory address) ๐งฉ
5.1.3. CONTROL_REJECT ๐ โโ๏ธ
The "To reject the control" (CONTROL_REJECT) instruction is sent from JCP as the negative response to a CONTROL_REQ ๐ Its fields look like this:
OPCODE = 4
PCK = %b00
CHN = 0
ASK = 1. The instruction does not need to be responded. This flag
specifies presence of the REQ_ID field.
EXT = 0/1
OPR_LENGTH = 1/2 ; Depends on presence of the control parameters
profile field.
REQ_ID - The value is taken from the instruction CONTROL_REQ
Operands:
2 octets: The basic error code. The zero-value is not
available.
2 octets: The additional error code.
4 octets: The control parameters profile (see section 5.1.1),
that is allowed by JCP. This is optional field.
The optional extension headers:
_INACT_TIME - This header contains the inaction time (see
section 5.7).
_MSG - contains the arbitrary error description.
5.2. Task Initiate ๐
The job runs on several nodes at the same time, and each of those nodes needs its own matching task ๐คนโโ๏ธ It's one task per job on each node, and each task has to be connected to exactly one job ๐
The task gets initiated together with the job on the node that created the job ๐ฃ On the other nodes, the task starts when the first request to open a session connection for that job arrives. That request contains GJID, and GJID contains the JCP address ๐ฎ The node needs the sanction from JCP before the task can start. If the session-open request came from the JCP node, though, the sanction isn't needed ๐
5.2.1. TASK_REG ๐งพ
The "To register a task" (TASK_REG) instruction is sent from the node that's initiating the task over to the JCP of the remote node ๐ฐ๏ธ Its fields look like this:
OPCODE = 6/7/8 ; For length CTID of 2/4/8 octets.
PCK = %b00
CHN = 0
ASK = 1
EXT = 0/1
OPR_LENGTH = 2-8 ; Depends on length of the GTID and LTID.
REQ_ID - The value is assigned by the sender node protocol and
then will be sent in the response.
Operands:
2/4/8 octets: CTID of the task initiated the job. It CTID is a
part GJID from the instruction SESSION_OPEN.
4-16 octets: GTID, assigned on the node, initialed session
connection. GTID is formed of sender addresses (at
transport layer) and field LTID of the instruction
SESSION_OPEN.
2/4/8 octets: LTID, assigned on the node, initialed the task
(by the sender of this instruction).
The optional extension headers:
_INACT_TIME - This header contains the inaction time (see
section 5.7).
A TASK_REG has to go out only if the task with the given GJID hasn't already been initiated on the node ๐ฆ
JCP confirms the task initiation when both of these are true:
- A task with the received GTID is already registered on JCP.
- A task with the LTID for the requesting node hasn't been registered.
In every other case, JCP won't confirm the task ๐
If JCP confirms the task, it sends the TASK_CONFIRM instruction. Otherwise it's TASK_REJECT โจ
5.2.2. TASK_CONFIRM ๐ซ
The "To confirm the task" (TASK_CONFIRM) instruction is sent from JCP as the positive response to a TASK_REG ๐ฅณ Its fields look like this:
OPCODE = 9
PCK = %b00
CHN = 0
ASK = 1. The instruction does not need to be responded. This flag
specifies the field REQ_ID presence.
EXT = 0/1
OPR_LENGTH = 1/2 ; Depends on length of the CTID.
REQ_ID - The value is taken from the instruction TASK_REG.
Operands:
4/8 octets: The CTID assigned to the task on the JCP.
The optional extension headers:
_JOB_NAME - This header contains the name of the Job.
5.2.3. TASK_REJECT ๐ซ
The "To reject the task" (TASK_REJECT) instruction is sent from JCP as the negative response to a TASK_REG ๐ค Its fields look like this:
OPCODE = 10
PCK = %b00
CHN = 0
ASK = 1. The instruction does not need to be responded. This flag
specifies presence of the REQ_ID field.
EXT = 0/1
OPR_LENGTH = 1
REQ_ID - The value is taken from the instruction CONTROL_REQ
Operands:
2 octets: The basic error code. The zero-value is not
available.
2 octets: The additional error code.
The optional extension headers:
_INACT_TIME - This header contains the inaction time (see
section 5.7).
_MSG - contains the arbitrary error description.
5.2.4. TASK_CHK ๐
For safety reasons, a node that has received a request to open a session connection can check with JCP on the node that initiated the connection, even if the task was already initiated ๐ก๏ธ
The "To check up the task" (TASK_CHK) instruction is sent from the node that has received the SESSION_OPEN instruction (the request to establish a session connection) over to JCP. The task with the given GJID must already exist on that node. The TASK_CHK format matches TASK_REG, with OPCODE = 11. JCP forms its responses to TASK_CHK in a similar way to TASK_REG instructions ๐
JCP confirms a TASK_CHK if a task with the received GTID and LTID is already registered on JCP โ
Sending TASK_CHK is optional ๐ธ
5.3. Establishment of session connection ๐
A session connection is established between two tasks of one job ๐ค The VM initiates the connection, and it's used to exchange instructions between VMs ๐ฅ๏ธ๐ฅ๏ธ
One session connection can only be connected to one task on a node. A task can have several connections with different nodes, but only one session connection with one GJID can exist between two nodes โ๏ธ
The request to establish a session connection includes the global job identifier GJID. If a node receives a request to establish a connection with a GJID that isn't present on that node, the VM must create a new task. If the task has already been initialized, the new task isn't created ๐งโโ๏ธ
The session connection has to be set up over TCP ๐ Once that's up, the instructions that don't need an execution response can go over UDP โจ One TCP connection can serve several session connections, and one session connection can use several TCP connections ๐ฆ
The protocol also works without a session connection at all ๐ธ The node must have a VM by default, and that VM has to run instructions without any connection being set up first.
When a session connection is established, the two sides agree on the VM type and on which subset of the protocol functions they'll use ๐ The session connection UMSP may be asymmetrical. That means the two sides of one connection can be attached to different VM types and offer different subsets of functions ๐
If the zero-type VM is used when establishing a session connection, it means the group VM (see section 9) ๐ง The zero-value for a realization VM is not allowed ๐
The handshake can be anywhere from 2-way up to 8-way ๐
5.3.1 SESSION_OPEN โจ
The instruction "To open a session" (SESSION_OPEN) starts a session connection and sets its parameters during the handshake ๐ Its field values are:
OPCODE = 12
PCK = %b00/11. In the first instruction (initial) the value of
this field is set to %b00. In all subsequent -
%b11.
CHN = 0
ASK = 1
EXT = 0/1
OPR_LENGTH = 6 - 10 ; Depends on length GJID and LTID.
SESSION_ID - In the first instruction this field is absent. In all
subsequent, it contains the identifier of sessions,
assigned by the instruction receiver.
REQ_ID - This field contains the session connection identifier,
assigned by the instruction sender.
Operands:
2 octets: The VM type required from the addressee.
2 octets: The VM version required from the addressee.
4 octets: The profile of connection required from the
instruction addressee.
2 octets: The VM type of the sender.
2 octets: The VM version of the sender.
4 octets: The profile of connection given by the instruction
sender.
2 octets: The number of 256 octet blocks in the buffer,
allocated for session ("window"), on the side of the
sender of this instruction (see section 7.4). The
zero-value specifies absence of the buffer.
4-16 octets: GJID.
4/8 octets: LTID of the sender task, assigned on the node -
sender of the instruction. It is used in the
instruction TASK_REG (as a part of the field GTID).
If the VM type and version the addressee is asked for are 0, the receiving node picks the VM type on its own and reports it back in the response ๐ฆ Setting up a connection without binding it to a VM or a VM group is not allowed ๐
Up to 7 SESSION_OPEN instructions can be sent in total while the connection is being set up ๐ SESSION_ACCEPT is the response that says yes, and SESSION_REJECT is the one that says no ๐
A connection can be refused at any step ๐ธ But on the eighth step, the sides have to either confirm the connection or refuse it, no in-between ๐ญ
During setup, these two things can change:
- VM type and VM version;
- profiles of connection.
Now, if a repeated request to open a session connection comes in from a specific node while a connection with that received GJID is already up, there are two possible outcomes ๐
- If the request came from the node JCP, then:
- the existing task has to be finished urgently, and all the dynamic resources that belong to it have to be deallocated ๐งน;
- a task gets started again without asking the JCP for sanction a second time ๐ฅ;
- the establishment of the connection gets confirmed โจ.
- If the request did not come from the JCP node, the establishment of the new session connection has to be refused. The existing task doesn't need to be changed ๐ซถ
5.3.2 SESSION_ACCEPT ๐
The instruction "To accept the session" (SESSION_ACCEPT) is the positive reply to a session connection being set up ๐ Its field values are:
OPCODE = 13
ASK = 1
PCK = %11
EXT = 0/1
CHN = 0
OPR_LENGTH = 0
SESSION_ID - This field contains the session connection identifier
of assigned by the node of the addressee of the
instruction.
REQ_ID - This field contains the session connection identifier,
assigned by the instruction sender.
5.3.3 SESSION_REJECT ๐
The instruction "To reject the session" (SESSION_ACCEPT) is the negative reply to a session connection being set up ๐ฅ Its field values are:
OPCODE = 14
ASK = 0
PCK = %b11
EXT = 0/1
CHN = 0
OPR_LENGTH = 1
SESSION_ID - This field contains the session connection identifier
of assigned by the node of the addressee of the
instruction.
Operands:
2 octets: The basic error code. The zero-value is not
available.
2 octets: The additional error code.
The optional extension headers:
_MSG - contains the arbitrary error description.
5.3.4 Connection Profile ๐ง
The connection profile is a 4-octet field of flags ๐ The flags are named S0 through S31, and the number in the name tells you the bit's serial number ๐ข If a flag is set to 1, the function tied to it is provided โ If it's set to 0, that function is not provided (not required) ๐ The functions that get decided when the session connection is set up are described further down ๐
Here's the full flag list, grouped the way the original groups them:
Work with chains:
S0 - Use of fragmented instructions.
S1 - Use of sequences.
S2 - Use of transactions.
Establishment of connection:
S3 - Use the exchange of the data without the establishment of
connection.
S4 - Use the exchange of the data with the establishment of
connection.
The instructions format:
S5 - Reserved. Must have set to 0.
S6 - Use of 16-octet address in the exchange instructions.
S7 - Use of the compressed form of header of the instruction
(OPR_LENGTH < > %b111) is allowed
S8 - Use of the extension form of header of the instruction
(OPR_LENGTH = %b111) is allowed
S9 - Use of the extension headers with the data field up to 254
octets of length.
S10 - Use of the extension headers with the data field up to 4 *
10^9 octets of length.
S11-S15 Maximal length of the data field in operands in the 4
octet words. These bits are the common field. Maximal
length in octets is computed under the formula:
<max length> = (<value of this field> + 1) * 4.
If the value is equal %b1111, maximal length of the data
is defined by the instruction format.
S16-S19 These bits are the common field. In the profile required
from the addressee of the instruction, this field
contains the version of the UMSP. It must is set to the
value %b0001. In the profile given sender of the
instruction, this field contains priority of the job. The
more is value of this field, the more priority. The
priority of the job is used:
o In queues on sending to the transport layer for the
instructions of the job.
o For set of sending priority of the transport layer.
o For set of computing priority of the task.
S20 - making the border multiple of 4 octets. If S16 = 1:
(1) OPR_LENGTH = %b111
(2) Each extension header and the field of operands begin with
the border multiple of four octets.
(3) The necessary number of zero octets is added in the end of
each header.
S21 - Use of the procedures name of objects.
S22 - Use of the objects name.
The permissible instructions:
S23 - The response of the execution on VM (instruction RSP) is
provided.
S24 - Use of data reading and comparison instructions.
S25 - Use of data writing instructions.
S26 - Use of control transfer instructions.
S27 - Use of synchronize instruction.
S28 - Use of instructions of work witch objects.
S29 - Use of the immediate access to memory of object. If this
flag is set to 0, the access to object is solved only
through its procedures. If S28=0, this flag must be set to
0.
S30 - Use of instruction MVRUN in zero-session.
S31 - Reserved. Must have set to 0.
5.4 Session Closing ๐
Only the node that started the session connection is allowed to start closing it ๐ That node uses the SESSION_CLOSE instruction for this, and the break-up procedure is a 3-way handshake ๐ค There's also an unconditional emergency end of the connection, and any node is allowed to send that one ๐จ
Let's say node A started the session and node B is the other side ๐ Node A has to send SESSION_CLOSE to close the session. After sending it, node A is allowed to keep sending instructions, which means it has refused to close the connection ๐ Response instructions (see section 6) don't affect how the connection closes โจ A node that has sent SESSION_CLOSE doesn't run a timeout, so it can wait for a response forever if it wants ๐ฅน
Once node B gets SESSION_CLOSE, it sends back RSP_P ๐ A zero basic return code means it agrees to close the session, and a non-zero basic return code cancels the closing ๐ After sending a positive response, node B must not use the connection for 30 seconds ๐ฐ๏ธ If node B doesn't receive SESSION_ABEND, or any instruction other than a response instruction, from node A by the time that's up, it sends SESSION_ABEND itself and considers the session connection closed ๐
Node A sends SESSION_ABEND after it gets a positive response to SESSION_CLOSE ๐ฆ After that, the connection is considered closed ๐ธ Node A can also back out of closing the connection by sending any instruction, NOP included ๐ซถ When it does that, the closing procedure is interrupted, and the session connection goes back to the working state ๐
5.4.1 SESSION_CLOSE ๐ง
The instruction "To close the session" (SESSION_CLOSE) starts the end of a session connection ๐ Its field values are:
OPCODE = 15
PCK = %b01/11
CHN = 0
ASK = 0
EXT = 0/1
OPR_LENGTH = 0/1
SESSION_ID - Contains the session identifier assigned by the
addressee.
Operands:
2 octets: The basic termination code.
2 octets: The additional termination code.
The optional extension header:
_MSG - contains the arbitrary message.
The operands are optional, bestie. If they're absent, it's the same as the zero exit code. ๐
5.4.2 SESSION_ABEND ๐
SESSION_ABEND is the "abort the session, no drama" instruction ๐ญ. The node that sends it finishes the data exchange on the connection at both sides, and it doesn't wait around for responses from any other node. Here's the field layout:
OPCODE = 16
PCK = %b01/11
CHN = 0
ASK = 0
EXT = 0/1
OPR_LENGTH = 0/1
SESSION_ID - Contains the session identifier assigned by the
addressee.
Operands:
2 octets: The basic termination code.
2 octets: The additional termination code.
The optional extension header:
_MSG - contains the arbitrary message.
The operands may be absent. That's equivalent to the zero termination codes. โจ
5.5 Task Termination ๐
A task finishes during the job's normal wrap-up, once the user application is done working. That procedure is covered in the next item. A task can also need to finish no matter what the job is doing, and that happens when:
- There are not enough computing resources to keep the task running on the node;
- The node finishes its work;
- VM has accepted such a decision for internal reasons.
The resources a task has allocated can live on any node the job runs on, so every node must be notified when a task ends. ๐ง
The node that's finishing the task must abnormally close all session connections tied to that task, by sending SESSION_ABEND. ๐
5.5.1 TASK_TERMINATE ๐ฆ
TASK_TERMINATE is sent from the node where the task finished over to JCP. Here are its fields:
OPCODE = 17
PCK = %b00
CHN = 0
ASK = 0
EXT = 0/1
OPR_LENGTH = 2/3 ; Depends on the length of CTID.
Operands:
2 octets: The basic termination code.
2 octets: The additional termination code.
4/8 octets: CTID.
The optional extension header:
_MSG - contains the arbitrary message.
After sending TASK_TERMINATE to JCP, the node sends ABEND_SESSION on every session connection attached to the task. After that, the task counts as completed. โจ
If the basic return code in TASK_TERMINATE is 0, it's not required to tell other nodes that the task ended. That happens when the task didn't allocate any dynamic resources. If the basic return code is not 0, JCP must notify the other nodes the job is running on about the task end, once it receives TASK_TERMINATE. JCP is responsible for notifying all nodes of the job about the task end. ๐ซถ
5.5.2 TASK_TERMINATE_INFO ๐ฅ
TASK_TERMINATE_INFO is how the task end gets announced. JCP sends it to the other nodes the job is running on. Here are its fields:
OPCODE = 18
PCK = %b00
CHN = 0
ASK = 0
EXT = 0/1
OPR_LENGTH = 2-5 ; Depends on the length of GTID.
Operands:
2 octets: The basic termination code.
2 octets: The additional termination code.
4-16 octets: GTID of the terminated task. JCP forms GTID from
LTID (from the instruction TASK_REG) and address
of transport layer of the task.
The optional extension header:
_MSG - contains the arbitrary message.
The termination codes come straight from TASK_TERMINATE. When a node receives TASK_TERMINATE_INFO, it must delete (make invalid) every reference to resources for the node the completed task was working on. ๐งน
5.6 Job Completion ๐
A job is finished when the user application attached to it on the node where it started is finished. The job usually ends on VM's initiative. It can also be completed on JCP's initiative, either when the job's lifetime runs out or when the JCP node stops working. ๐
5.6.1 JOB_COMPLETED ๐
JOB_COMPLETED is sent from the node that started the job over to the JCP side. Its fields look like this:
OPCODE = 19
PCK = %b00
CHN = 0
ASK = 0
EXT = 0/1
OPR_LENGTH = 2/3 ; Depends on the CTID length.
Operands:
2 octets: The basic completion code.
2 octets: The additional completion code.
4/8 octets: CTID of the completed task of the job. CTID is a
part GJID of the job.
The optional extension header:
_MSG - contains the arbitrary message.
After sending JOB_COMPLETED to JCP, the node sends ABEND_SESSION on all session connections of the job that are connected. After that, the job counts as completed. โจ
JCP must notify the nodes the job is running on about the job's end, as soon as it receives JOB_COMPLETED. JCP is responsible for notifying all nodes of the job about the job's end. ๐ซถ
TASK_TERMINATE_INFO may be sent on JCP's initiative if the task's node terminated abnormally. ๐
5.6.2 JOB_COMPLETED_INFO ๐
JOB_COMPLETED_INFO announces that the job is over. JCP sends it to the other nodes the job is running on. Here are its fields:
OPCODE = 20
PCK = %b00
CHN = 0
ASK = 0
EXT = 0/1 ;
OPR_LENGTH = 2-5 ; Depends on the GJID length and presence of
fields completion code.
Operands:
2 octets: The basic completion code.
2 octets: The additional completion code.
4-16 octets: GJID of the completed job.
The optional extension header:
_MSG - contains the arbitrary message.
The completion code fields are optional. ๐
The completion code fields come from JOB_COMPLETED. When a node receives JOB_COMPLETED_INFO, it must do the following:
- Remove all session connections connected to the task. It isn't necessary to send network primitives for this.
- Abnormally finish the task of the job and deallocate all dynamic resources of the task.
JOB_COMPLETED_INFO is used to end the job on JCP's initiative, either at the end of its lifetime or when the JCP node stops working. In those cases, the node that started the job is the first addressee of the instruction. ๐ง
JCP considers the job completed once it has sent all the JOB_COMPLETED_INFO instructions. โจ
5.7 Activity Control of Nodes ๐ฆ
UMSP brings together nodes that can be arranged in any way on the network and that don't share uniform controls. Each node can be disconnected or reloaded at any moment, and the other nodes might not be told about it. Breaking a transport connection, or setting one up again, can't be taken as a sign that a node disconnected or restarted. Controlling transport connections isn't part of the UMSP protocol, and having a transport connection isn't required. ๐ธ
A single task on a node can also be finished in an emergency. In that case, the procedure described in section 5.5.1 must be executed. If that procedure can't be executed, the node's work must be abnormally finished. ๐ญ
JCP handles the activity control of nodes. For this, TASK_REQ, the status request instruction, is sent periodically between the tasks on nodes and JCP. ๐
When JCP detects that a node has deactivated, it can take the following actions:
- If the task that started the job has finished, the job is considered completed. JCP sends JOB_COMPLETED_INFO to all other nodes the job was running on.
- JCP sends TASK_TERMINATE_INFO to all other nodes of the job if the task that didn't start the job has finished.
Deactivating the JCP node puts a restriction on the GJID it had been assigned, once it reloads. There are two likely variants:
- The JCP node disconnected normally. It sent JOB_COMPLETED_INFO to every node it controlled. In this case, it can be assigned any GJID after reloading.
- The JCP node had an emergency disconnect. It didn't inform all nodes about the deactivation. In this case, after reloading, it must guarantee that the new GJID won't coincide with any GJID that existed before the reload, for two maximal intervals of inactivity time (the ones this JCP sets). ๐ฅ
Reloading a node that isn't JCP doesn't put any restriction on the LTIDs established on that node. ๐
5.7.1 _INACTION_TIME โฐ
The extension header _INACTION_TIME lets a node (non-JCP) set its inaction time. Here are its fields:
HEAD_CODE = 2
HEAD_LENGTH = 1;
HOB = 1
DATA contains:
2 octets: The inaction period. The number of 0,5 second
intervals, through which the activity of the node - sender of
the instruction from the side JCP - will be checked.
The inaction period must be more than three intervals of the maximal delivery time at the transport layer. Time spent waiting in the queue to the transport layer doesn't affect the timeout. ๐ง
The _INACTION_TIME header may be attached to these instructions:
- TASK_REG. In this case, one condition must be met: there must be no other active tasks on the node that are controlled by the addressee's JCP. A zero value means the activity check isn't used. If the header is absent, the inaction period must be set on the JCP.
- TASK_REJECT, if the time since TASK_REG doesn't fit for the JCP.
- TASK_CONFIRM, if TASK_REG didn't have this header.
If JCP receives TASK_REG with the _INACTION_TIME header attached, it must check whether there are active tasks with the sender node, since that can mean the node was reloaded. If such tasks exist, JCP must carry out the task-end procedure described in section 5.6.2 for each one of them. TASK_CONFIRM must only be sent after that. ๐
5.7.2 STATE_REQ ๐
STATE_REQ, the "State Request" instruction, goes from JCP to a specific task on another node. Its fields:
OPCODE = 21
PCK = %b00
CHN = 0
ASK = 0
EXT = 0
OPR_LENGTH = 1/2 ; Depends on the LTID length.
Operand:
4/8 octets: LTID, established on the node of the instruction
addressee.
STATE_REQ is sent to a defined task, but it's about the node. It gets sent if no instruction went between the node and JCP during the inactive time. A task that's activated after the last STATE_REQ was sent doesn't affect the activity control. ๐ฆ
The node sends TASK_STATE back as its reply to STATE_REQ ๐. While it waits for that reply, it uses a timeout of one inaction period โณ. If that timeout runs out, the node is considered switched-off ๐ด.
If the node doesn't hear anything from JCP for two inaction intervals, it's considered that JCP has finished the work ๐. What the node does then is described in section 5.6.2, when it gets JOB_COMPLETED_INFO. Checking for this condition is OPTIONAL for the node ๐ซถ.
If JCP has no active tasks connected to a given node, the control of that node's activity won't be carried out at all ๐.
5.7.3. TASK_STATE โจ
The instruction "Task State" (TASK_STATE) is sent from the task in question to JCP. It's the response to STATE_REQ ๐ Here's its field layout:
OPCODE = 22
PCK = %b00
CHN = 0
ASK = 0
EXT = 0
OPR_LENGTH = 1/2/3 ; Depends on the CTID length.
Operands:
1 octet: The state code of task. The following values are
defined for this field:
%x01 - The task is active and has active session
connections.
%x02 - The task is active and have no session connections.
%x03 - The task is active, have no session connections and
have no resources, allocated on the node.
%x04 - The task is completed.
1/3 octets: Reserved. If OPR_LENGTH = 1, then this field has
length 1 octet, else 3 octets. JCP MUST NOT check
the value of this field. It is established in zero
value by sending.
2/4/8 octets: CTID connected with LTID from the instruction
STATE_REQ.
So if OPR_LENGTH = 1, the reserved field is one octet and the CTID is two octets ๐ฆ. In every other case, the reserved field is 3 octets and the CTID is not less than 4 octets ๐.
5.7.4. NODE_RELOAD โจ
The instruction "The node was reloaded" (NODE_RELOAD) goes to JCP as the negative response to a STATE_REQ instruction ๐ It has these field values:
OPCODE = 23
PCK = %b00
CHN = 0
ASK = 0
EXT = 0
OPR_LENGTH = 1/2 ; Depends on the LTID length.
Operands:
4/8 octets: LTID. The value is taken from the instruction
STATE_REQ.
The RELOAD_NODE instruction tells JCP that the task with the given LTID for the given JCP is absent from the node ๐ง When JCP receives it, JCP MUST do the following:
- Send STATE_REQ to all tasks on the node that were initiated before the penultimate STATE_REQ instruction was sent.
- Wait for one inaction interval to end after the last STATE_REQ instruction was sent (the one that got the negative response).
- Send STATE_REQ to all tasks on the node that were initiated between the last and penultimate STATE_REQ instructions (not including the ones from item 1).
For every STATE_REQ instruction, either the positive response (TASK_STATE) or the negative response (RELOAD_NODE) MUST be sent โจ
5.8. Work without session connection ๐ธ
The protocol lets nodes exchange data without setting up a session connection ๐ฆ In that case, the job and tasks aren't initialized, and JCP isn't used.
The format of instructions sent without a connection is exactly the same as for instructions sent over session connections. The only difference is that the SESSION_ID field is zero or PCK = %b00 ๐
A node that supports work without a session connection MUST have a VM, which runs the instructions sent without a connection by default ๐ Those instructions actually run inside that VM's so-called zero-session (or zero-task) ๐ซถ The memory address space of this VM can be accessed without setting up a connection ๐
The SESSION_INIT instruction with SESSION_ID = 0 and REQ_ID = 0 lets you set the parameters for your zero-session and ask for the zero-session parameters of the addressee node ๐
If the node that gets this instruction supports the requested profile, it sends back SESSION_ACCEPT. If it doesn't, it sends a reply SESSION_INIT in which SESSION_ID and REQ_ID are also 0 โจ Those session-init instructions don't really set up a connection, but they do carry information. Data can be exchanged through the zero-session regardless of whether one exists ๐ธ
Working without a connection has these restrictions:
- The chain MUST be sent only if it's located entirely within one segment of the transport layer ๐
- You can't request memory allocation or create objects (except with the MVRUN instruction). These objects aren't tied to a specific job, and they don't automatically release their resources when the job that created them ends ๐
- Function parameters and return values MUST NOT contain pointers, because the node can be reloaded at any moment ๐ญ Otherwise, the pointers could become invalid or point to other objects.
The protocol can't check these conditions. Making them happen is entirely up to the VM ๐ซถ
Work without a session connection may be used in the following systems:
- Simple devices that don't have an operating system ๐ง
- Servers handling lots of requests (they use fewer connection resources for work without connections) ๐ป
- Systems that need fast responses to rare requests (when keeping a connection open isn't worth it) ๐
6. Instructions of Exchange between VM ๐
Instructions for exchange between VMs use OPCODE values in the range 128 - 223 ๐ Depending on the length of the operands field, several instruction formats may be defined for a single OPCODE. The full instruction format is defined by the combination of the OPCODE and OPR_LENGTH values โจ
If ASK = 1 in the instruction header, the instruction has the REQ_ID field ๐ REQ_ID is used to identify the response. Its value is specified by the VM, and the response is also formed by the VM ๐ซถ The protocol doesn't check the response and doesn't analyze the value of REQ_ID for instructions of exchange between VMs. The response is sent using one of these instructions: RSP, DATA, RETURN, ADDRESS, OBJECT or PROC_NUM ๐
Response instructions have ASK = 1, and the value from the confirmed instruction is recorded in REQ_ID. Response instructions don't need a response themselves ๐ฆ
Instructions of exchange between VMs MAY be sent through UDP if the following conditions are observed:
ASK = 0;- The instruction is located in one UDP segment.
Timeouts and repeated sending aren't used at the UMSP layer for instructions of exchange between VMs ๐ธ The reason is that instructions with low priority can take a very long time to send because of output queues. So the VM MUST decide on the timeout, since only the VM has the complete information about the type of data being transmitted ๐ Besides, the transport layer protocol MUST use timeouts ๐
A few VMs may be connected to the protocol on a node, and a VM may run several jobs at the same time ๐ง Each job may work in its own address space. The protocol decides which VM and job a received instruction should go to, based on the SESSION_ID value ๐
The local memory address sits in the instruction in a field that's 2/4/8 octets long ๐ If the memory address length in the instruction doesn't match the memory address length defined for the node, these options are possible:
- If the node's memory address length is 24 bits, the address is written at the end of a 4-octet field, and the initial (zero) octet is set to 0 ๐
- If the instruction format assumes a memory address length of at least 4 octets, the 2-octet address is placed in the last octets. The first 2 octets MUST be set to zero ๐ญ
- If the instruction is a member of a chain and its memory address is shorter than the one defined for the node, base-displacement addressing is assumed. If no memory base is assigned for the chain, the instruction is erroneous ๐
- If the instruction is not a member of a chain and its memory address is shorter than the one defined for the node, an abbreviated address is assumed. The complete address length MUST be obtained by padding the front of it with the required number of zero-value octets ๐
- In all other cases, the instruction is erroneous ๐
The complete 128-bit memory address is written in the operands in a 16-octet field ๐ฆ The reason for using the complete address is that extra information used by the node's memory control subsystem may be carried in its FREE field (see section 2.1) ๐ซถ If the FREE field of the complete address is set to zero, it is RECOMMENDED to use the local address in the operands โจ
The operands field has a length that is an integral number of 32 bits ๐ Alignment is done by padding the end of the field with zero-value octets if necessary ๐
Header fields of instructions that aren't defined in the format descriptions are used as described in section 3 ๐
The transfer control instructions JUMP, CALL, CALL_BNUM and CALL_BNAME may contain information about the sender's VM ๐ง If the sender's VM type and VM version are included in the instruction, the call parameters are formed in the format of the sender's VM. Otherwise, the call parameters are in the format defined by the addressee's VM ๐ Code is always tied to a specific VM ๐
All instructions of the protocol work with binary data and don't provide any format transformation operations ๐ฅ
6.1. Data Reading/Writing Instructions โจ
6.1.1. REQ_DATA
okay so REQ_DATA ("To request a data") is how you ask the remote node for data ๐ฆ There are two versions, one with a length field of 2 octets and one with 4 octets ๐
OPCODE = 130/131 ; For length of the length field of 2/4
octets.
OPR_LENGTH = 1/2/3/5 ; Depends on address length.
Operands:
2/4 octets: The length field. The number of the required data in
octets.
2/4/8/16 octets: The memory address of the required data.
the DATA instruction with the requested bytes comes back as the reply ๐ if the data can't be sent, you get an RSP with a non-zero basic return code instead ๐
6.1.2. DATA
DATA ("The data") is the reply to REQ_DATA and OBJ_REQ_DATA ๐ง
OPCODE = 132
OPR_LENGTH = 0 - 65535 ; Depends on the immediate data length of
the operand.
Operands:
0 - 262140 octets: Immediate data. If OPR_LENGTH = 0, this
field are absent.
Extension headers:
_DATA - Contains immediate data. If OPR_LENGTH <> 0, this
header are absent.
the extension header comes into play when the data is bigger than the max operands field size ๐ธ you can't send the data in the operands AND the extension header at the same time, that's a no-go ๐ โโ๏ธ also, to make the length a multiple of 4 octets, you pad the end of the field with 1 to 3 zero-value octets ๐ซถ
6.1.3. WRITE
WRITE ("To write the data") is how you write data onto the remote node โ๏ธ
OPCODE = 133/134/135/136 ; For memory address length of 2/4/8/16
octets.
OPR_LENGTH = 1 - 65535 ; Depends on length of the immediate
data.
Operands:
2/4/8/16 octets: The memory address for writing the data.
0 - 262136 octets: Immediate data for write.
Extension headers:
_DATA - Contains immediate data. This header is present only,
if the data does not contain in operands.
here's the vibe check ๐ with a 2 octet address, the data has to be 2 octets. For every other case, the address has to be at least 4 octets and the data has to be a multiple of 4 octets. Also, the data can't be sent in the operands AND the extension header at once ๐
the RSP is the reply to WRITE, and a zero basic return code means it went through normally ๐
6.1.4. WRITE_EXT
WRITE_EXT ("The extension writing of data") is also for writing data on the remote node, but it's the flexible one ๐ฆ the data can be anywhere from 1 to 262132 octets, going up one octet at a time โจ
OPCODE = 137
OPR_LENGTH = 3 - 65535 ; Depends on length of the immediate data.
Operands:
1 octets: Always set to zero.
3 octets: The number of the write data in octets. The zero-
value is not available.
4 - 262132 octets: Immediate data for write. The data length
must be multiple of 4 octets.
4/8/16 octets: The memory address for writing the data.
to make the immediate data a multiple of four octets, pad the end of the field with 1 to 3 zero-value octets ๐
again, the reply is an RSP and a zero basic return code means normal execution ๐
6.2. Comparison Instructions
6.2.1. CMP
CMP ("To compare") does binary data comparisons ๐
OPCODE = 138/139/140/141 ; For the address length of 2/4/8/16
octets.
OPR_LENGTH = 1 - 65535 ; Depends on length of the immediate
data.
Operands:
2/4/8/16 octets: The memory address for compared data.
2 - 262136 octets: The immediate data for the comparison.
same deal as WRITE ๐ฏ with a 2 octet address the data length must be 2 octets. In every other case the address can't be shorter than 4 octets, and the data length has to be a multiple of four octets ๐
6.2.2. CMP_EXT
CMP_EXT ("The extension compare") is the binary comparison with the flexible sizing ๐ the data can be 1 to 262132 octets, going up one octet at a time ๐ฆ
OPCODE = 142
OPR_LENGTH = 3 - 65535 ; Depends on length of the immediate data
and the address.
Operands:
1 octet: Always set to 0.
3 octets: The length of compared data in octets. The zero-value
is not available.
4 - 262132 octets: The immediate data for the comparison. The
length of field is multiple of 4 octets.
4/8/16 octets: The memory address of compared data.
to make the immediate data a multiple of four octets, pad the end of the field with 1 to 3 zero-value octets ๐
6.2.3. Response to Comparison Instructions
RSP is the reply to CMP, CMP_EXT and OBJ_CMP (more on that one below ๐) ๐ If the comparison actually ran, the basic return code is zero. The additional return code tells you how it went: -1 if the data at the address is less than the data in the operand, 0 if they're equal, and 1 if the address data is more โจ If the comparison couldn't run at all, the basic return code of the RSP must be non-zero ๐
6.3. Control Transfer Instructions
6.3.1. JUMP, CALL
JUMP ("Unconditional jump") and CALL ("To Call-subroutine")_ have the same format and only differ by their OPCODE ๐ฏโโ๏ธ
OPCODE = 143/144 ; Correspondingly for the JUMP not containing
and containing the information about VM.
145/146 ; Correspondingly the CALL not containing and
containing the information about VM.
OPR_LENGTH = 2 - 65535 ; Depends on inclusion of the information
about VM, address length and parameters
length.
Operands:
2 octets: The VM type of the sender. If OPCODE=143/145 this
field is absent.
2 octets: The VM version of the sender. If OPCODE=143/145 this
field is absent.
4/8/16 octets: The address of memory, where is necessary to
transfer control.
2 octets: The number of 32 bit words in the call parameters
field.
4 - 262134 octets: The immediate data are the parameters of a
call.
here's how the receiving side handles control transfer ๐ง
- The memory address gets checked. If it's wrong, a negative RSP is sent back. At this stage, the parameters of the call may also get checked ๐
- If the memory address and the call parameters are good, a positive RSP goes out for JUMP. The sender treats JUMP as executed once it gets that response ๐ฆ
- For CALL, the reply to a successful execution is a RETURN. RETURN can carry returned values. If there's an exception in a thread of control that CALL created, an RSP with a non-zero basic return code gets sent instead of RETURN ๐
6.3.2. RETURN
RETURN ("Return of control") is used to return control from CALL, MVRUN, CALL_BNUM and CALL_BNAME (see below) ๐ธ those instructions have these field values:
OPCODE = 147
OPR_LENGTH = 0 - 65535 ; Depends on length of the immediate data.
Operands:
0 - 262140 octets: Immediate data returned from the subroutine.
if there's no returned value to send, the RETURN has no operands at all ๐ซถ the data format matches the instruction the response is for, so it follows the format of the VM of the sender or addressee โจ
the things to remember here: RETURN has no operands when there's nothing to return, and its format mirrors the instruction it's answering ๐
6.4. Memory Control Instructions ๐ง ๐
okay so UMSP gives you ways to split memory up for code and for data ๐ but it does NOT check whether your memory operations are correct ๐ the code and the data share one common address space, and the VM handles all the memory control, fully โจ
6.4.1. MEM_ALLOC ๐ธ
the instruction "To allocate a memory for the data" (MEM_ALLOC) is how you ask for memory to hold data ๐ซถ it looks like this:
OPCODE = 148
OPR_LENGTH = 1
Operands:
4 octets: The size of required memory in bytes.
if it works, you get back an ADDRESS, and if it doesn't, you get an RSP with a non-zero basic return code ๐ the address you get back can then be used by the protocol in reading/writing, comparison and synchronization instructions ๐ฆ
6.4.2. MVCODE ๐ง
the instruction "To move the code" (MVCODE) moves executable code from one node to another ๐ here's the layout:
OPCODE = 149
OPR_LENGTH = 1 - 65535 ; Depends on length of the code field.
Operands:
2 octets: The VM type of addressee.
2 octets: The VM version of addressee.
0-262136 octets: contains the executable code.
The extension headers:
_DATA - contains the executable code. This header is present
only, if the code does not contain in operands.
the code is always tied to a VM of one definite type ๐ the protocol treats the code field as totally transparent, which means the VM of the sender builds it and it must contain all the information the VM of the receiver needs ๐ญ the code must not be sent in operands AND in the extension header at the same time, so pick one, bestie ๐ฅ
if it works, you get an ADDRESS back, and if it doesn't, you get an RSP with a non-zero basic return code ๐ the code you moved with MVCODE can then be run with JUMP or CALL โจ
6.4.3. ADDRESS ๐ฆ
the instruction "The memory address" (ADDRESS) is the positive response to MEM_ALLOC and MVCODE ๐ here's how it's shaped:
OPCODE = 150
OPR_LENGTH = 1/2/4; Depends on length of the address.
Operands:
4/8/16 octets: The address of the allocated memory.
for MEM_ALLOC, the address points at the first byte of the allocated data area ๐ for MVCODE, the contents of the address are defined by the VM that the code is connected to ๐ซถ
6.4.4. FREE ๐งน
memory that was allocated with MEM_ALLOC and MVCODE must be explicitly released ๐ค that's what the instruction "To free the memory" (FREE) is for ๐ it looks like this:
OPCODE = 151
OPR_LENGTH = 1/2/4; Depends on length of the address
Operands:
4/8/16 octets: the address of free memory.
the VM must free this memory automatically at the end of the task on the node ๐ so it's not totally on you, but still, know your rights ๐
6.4.5. MVRUN ๐
the instruction "To move and run" (MVRUN) does two things at once: it moves a code AND runs it ๐ฅ it looks like this:
OPCODE = 152
OPR_LENGTH = 1 - 65535 ; Depends on length of the code field.
Operands:
2 octets: The addressee VM type.
2 octets: The addressee VM version.
4 - 262136 octets: Contains an executable code.
The extension headers:
_DATA - Contains an executable code. This header is present
only, if the code does not contain in operands.
the executable code is a transparent buffer of binary data as far as the protocol is concerned ๐ง its format is defined by the VM, and it must contain everything the loader of the addressee VM needs, including the parameters of a call ๐ซถ
the code must not be sent in operands and in the extension header at the same time ๐
the answer to MVRUN is formed similarly to the answer to CALL ๐ธ you don't have to release the memory that this instruction allocated for the code, since the VM deallocates it itself ๐
6.5. Other Instructions โจ
no, I mean, 6.5 is a ## heading, so here it is properly below
6.5. Other Instructions โจ
6.5.1. SYN ๐
the instruction "To Synchronize" (SYN) sends a single message about a data change ๐ it looks like this:
OPCODE = 153/154/155 ; For length of the address 4/8/16 octets.
OPR_LENGTH = 2 - 65535; Depends on length of the data
Operands:
4/8/16 octets: The memory address of the tracking data.
2 - 131068 octets: The initial data. Length of the data must be
multiple of two octets.
2 - 131068 octets: A mask for comparison. Length of this field
is equal to length of a field of the initial
data.
the tracking data lives at the memory address in the first operand ๐ฆ it gets compared to the initial data in the second operand, and if they don't match, the data is considered to have changed ๐ฅ the third operand lets you set a mask for the comparison, and any bits set to one in the mask mark the bits in the data whose change you want to track ๐
here's what the answer might look like:
- if the address of local memory is incorrect, an RSP with a non-zero basic return code is sent back ๐
- if the data does not change, nothing is sent in the response ๐
- if the data has changed, a DATA instruction with the new value of the traced data is sent ๐
6.5.2. NOP ๐ซง
the instruction "No operation" (NOP) is basically the protocol's little filler message ๐ธ it looks like this:
OPCODE = 156
OPR_LENGTH = 0 - 65535
Operands:
0 - 262140 octets: Encapsulated data.
Extension headers:
Any Extension headers.
NOP is meant for two jobs:
- sending control extension headers when there are no other instructions to send in a session ๐ง
- encapsulating fragmented instructions and transactions with the established flag of special processing (see section 7) ๐
6.6. Work with Objects ๐
the protocol has a set of instructions that expand on RPC [6] ๐ the big difference is that, unlike RPC, UMSP lets you address memory on remote nodes right away, and lets you send pointers in parameters and return values ๐ฅ
a UMSP object is identified by a 4-octet number ๐ the values are split into these ranges:
I -> %x00000000 - 1FFFFFFF are assigned for standard objects
II -> %x20000000 - 3FFFFFFF are assigned for users objects
III -> %x30000000 - 4FFFFFFF free
IV -> %x50000000 - DFFFFFFF transient
V -> %xE0000000 - FFFFFFFF reserved
- objects in range I must be definite and standard, and their interface specifications must be published ๐ the protocol doesn't assume private or undocumented interfaces for standard objects ๐
- objects in range II must be registered, but publishing their interface specifications may be optional ๐ซถ these numbers are used when you need to avoid possible conflicts between systems from different manufacturers ๐
- range III is free to use ๐ฆ objects on these numbers can be created statically or dynamically, and they can have any interfaces at all โจ
- all objects in ranges I, II and III are shared by all jobs on the node, including the zero-session ๐ their interfaces are reachable by every task on the node, depending on the authentication parameters ๐
- range IV is for objects created dynamically within one job ๐ง these objects are the job's own isolated associative memory ๐ access to them must be granted to one job only, and the zero-session has no access to them at all ๐ค
the protocol gives access to object data as one continuous segment of memory ๐ object memory may or may not overlap with the flat local memory of the node ๐งฉ the offset field is used in the instructions that work with object data, and the offset writing rules are similar to the local address writing rules ๐
the address memory length of the node, which is defined for UMSP, limits the maximum data size of one object ๐ the instructions defined in this section allow working with associative memory whose theoretical limit on one node is 2^96 (7,9 * 10^28) Byte ๐คฏ
besides the number, an object has a version (2 octets long) and a realization (2 octets long) ๐ the protocol requires mandatory backward compatibility for all realizations of one version of an object ๐ซถ a new realization of a standard object may contain only added interfaces ๐ธ
if the version and/or realization of the object don't matter to the sender of the instruction, or aren't known to it, the instruction may contain zero fields for the version and realization of the object, or only a zero realization field ๐ง a zero version field with a non-zero realization field is not allowed ๐ โโ๏ธ
6.6.1. Reading/Writing of the Objects Data ๐
6.6.1.1. OBJ_REQ_DATA ๐ฅ
the instruction "To request the data of object" (OBJ_REQ_DATA) asks a remote node for object data ๐ซถ it looks like this:
OPCODE = 192/193 ; For length of the field of length 2/4 octets.
OPR_LENGTH = 3/4/5 ; Depends on length of the offset field.
Operands:
4 octets: The number of object.
2 octets: The version of object.
2 octets: The realization of object.
2/4 octets: The length of the required data in octets.
2/4/8 octets: Offset required data from the beginning of object
in bytes.
if the length field is 2 octets, the offset length must be 2 octets too ๐ in every other case, the length field and the offset length must be not less than 4 octets ๐ฅ
the DATA instruction with the required data is the reply to OBJ_REQ_DATA โจ if the data can't be transmitted, an RSP with a non-zero basic return code comes back instead ๐ญ
6.6.1.2. OBJ_WRITE ๐ค
the instruction "To write the data in object" (OBJ_WRITE) writes data into an object ๐ it looks like this:
OPCODE = 194/195/196 ; For length of the offset field of 2/4/8
octets.
OPR_LENGTH = 3 - 65535 ; Depends on the data length.
Operands:
4 octets: The number of object.
2 octets: The version of object.
2 octets: The realization of object.
2/4/8 octets: The offset in object for the data writes.
2 - 262128 octets: The immediate data for write.
The extension headers:
_DATA - Contains immediate data for write. This header is
present, only if the data is not present in operands.
if the offset field is 2 octets, the data length must be 2 octets too ๐ง in every other case, the offset length must be not less than 4 octets, and the data length is a multiple of four ๐ the data must not be sent in operands AND in the extension header at the same time ๐
an RSP is sent in reply to OBJ_WRITE ๐ฆ a zero basic return code means the normal execution went through ๐
6.6.1.3. OBJ_WRITE_EXT โจ
Okay so OBJ_WRITE_EXT is "The extension writing of the data in object" ๐, and it's the one you use to write data into an object. The data can be anywhere from 1 to 262132 octets, going up in steps of 1 octet, which is lowkey huge ๐ฅ. Here's the field layout, bestie:
OPCODE = 197
OPR_LENGTH = 3 - 65535; Depends on the data length and the address
length.
Operands:
4 octets: The number of object.
2 octets: The version of object.
2 octets: The realization of object.
1 octet: Always set to 0.
3 octets: Length written down data in octets. The zero-value is
incorrect.
4 - 262124 octets: The immediate data for write. Length of the
data is multiple of 4 octets.
2/4/8 octets: Offset in object for the data write.
If the written-down data isn't a multiple of four octets, it gets padded with 1 - 3 zero octets at the end ๐ซถ
The RSP instruction is what comes back in reply to OBJ_WRITE_EXT ๐. A zero basic return code means normal execution, periodt ๐
6.6.2. Comparison Instructions of the Objects Data ๐ฆ
6.6.2.1. OBJ_DATA_CMP
OBJ_DATA_CMP, or "To compare the data of object," is for doing a binary comparison of an object's data against the immediate data in the operands ๐. The fields go like this:
OPCODE = 198/199/200 ; For length of offset field of 2/4/8
octets.
OPR_LENGTH = 3 - 65535; Depends on length of the data.
Operands:
4 octets: The number of object.
2 octets: The version of object.
2 octets: The realization of object.
2/4/8 octets: Offset in object for the compared data.
2 - 262128 octets: The immediate data for comparison.
Quick rule of thumb: when the offset field is 2 octets, the data length must be 2 octets. For every other case, the offset length must be not less than 4 octets and the data length is multiple to 4 octets ๐
The response to OBJ_DATA_CMP is described in section 6.2.3 ๐
6.6.2.2. OBJ_DATA_CMP_EXT
OBJ_DATA_CMP_EXT is the extended version, "The extension compare of data of the object," and it does the same binary comparison thing โจ. The big difference is the data can be 1 - 262132 octets, in steps of 1 octet. Here's the layout:
OPCODE = 201
OPR_LENGTH = 5 - 65535 ; Depends on length of the immediate data
and the address length.
Operands:
4 octets: The number of object.
2 octets: The version of object.
2 octets: The realization of object.
1 octet: Always set to 0.
3 octets: The length of compared data in octets. The zero-value
is incorrect.
4 - 262124 octets: The immediate data for the comparison. The
length of field is multiple of 4 octets.
4/8 octets: Offset in object for the compared data.
To make the immediate data a multiple of four octets, it gets padded with 1 - 3 zero-value octets at the end ๐ธ
The response to OBJ_DATA_CMP_EXT is described in section 6.2.3, same as before ๐ฆ
6.6.3. Execution of the Objects Procedures ๐ง
6.6.3.1. CALL_BNUM
CALL_BNUM ("To call the object procedure over number") transfers control to an object procedure, and you point at it by its number ๐ข. Here's how the fields look:
OPCODE = 202/203 ; Accordingly for the instructions not containing
and containing the information about VM.
OPR_LENGTH = 4 - 65535 ; Depends on inclusion of the information
about VM and call parameters length.
Operands:
2 octets: The VM type of the sender. If OPCODE=202 this field
is absent.
2 octets: The VM version of the sender. If OPCODE=202 this
field is absent.
4 octets: The number of object.
2 octets: The version of object.
2 octets: The realization of object.
4 octets: The number of the called procedure.
4 - 262128 octets: Parameters of the call.
Processing on the receiving side works basically the same as CALL (see section 6.3.1) ๐
6.6.3.2. CALL_BNAME
CALL_BNAME ("To call the object procedure over name") does the same job, but you use the procedure's name instead of its number ๐ท๏ธ. The fields:
OPCODE = 204/205 ; Accordingly for the instructions not
containing and containing the information
about VM.
OPR_LENGTH = 3 - 65535 ; Depends on inclusion of the information
about VM and call parameters length.
Operands:
2 octets: The VM type of the sender. If OPCODE=204 this field
is absent.
2 octets: The VM version of the sender. If OPCODE=204 this
field is absent.
4 octets: The number of object.
2 octets: The version of object.
2 octets: The realization of object.
4 - 262128 octets: Parameters of the call.
The extension header:
_NAME - Contains the name of the called procedure.
Receiving side processing is made similarly to CALL (see section 6.3.1) ๐ซถ
Now the name drama ๐: procedures of objects in ranges III and IV may have names. Procedures of objects in ranges I and II must not have a name on the UMSP layer. They must have the number only ๐ข
6.6.3.3. GET_NUM_PROC
GET_NUM_PROC ("To get the name of object procedure") lets you get the number of a procedure for objects in ranges III and IV, using the procedure name ๐. The fields:
OPCODE = 206
OPR_LENGTH = 2
Operands:
4 octets: The number of object.
2 octets: The version of object.
2 octets: The realization of object.
The extension header:
_NAME - Contains procedure name.
If it works, you get back PROC_NUM. If it doesn't, you get RSP with a non-zero basic return code ๐
6.6.3.4. PROC_NUM
PROC_NUM ("The procedure number") is sent in reply to GET_NUM_PROC ๐. Here's the layout:
OPCODE = 207
OPR_LENGTH = 3
Operands:
4 octets: The number of object.
2 octets: The version of object.
2 octets: The realization of object.
4 octets: The number of procedure.
6.6.4. The Objects Creation ๐๏ธ
Objects from ranges I and II (standard and assigned for the user) cannot be created on the remote node through the UMSP interface ๐ซ. They must be created only through the API of the VM. Objects from ranges III and IV can be created on the remote node by protocol instructions ๐
Real talk, creating objects from ranges I - III (the ones not tied to a specific job) is kind of a lot ๐ญ. Different jobs can have different memory address spaces, so pointers must be processed in the context of the job they came from. These objects also have to track when the job ends so dynamic resources get deallocated. Those requirements put some serious limits on these objects. The protocol doesn't impose any restrictions on objects from range IV ๐ฆ
The unique key that identifies an object on a node is its number. Objects from ranges III and IV can be given a name too. Objects from ranges I and II must not have names on the UMSP layer. Inside one task, you must not have two objects sharing one number or one name ๐ โโ๏ธ
6.6.4.1. NEW, SYS_NEW
NEW ("New object") and NEW_SYS ("New system object") look pretty similar. NEW makes an object in range IV, and NEW_SYS makes one in range III. Here are the fields:
OPCODE = 208/209; Accordingly for NEW/NEW_SYS.
OPR_LENGTH = 3
Operands:
2 octets: The addressee VM type.
2 octets: The addressee VM version.
2 octets: The version of object.
2 octets: The realization of object.
4 - 262136 octets: Immediate data necessary for creation of
object.
The extension headers:
_DATA - Contains immediate data, necessary for creation of
object. This header is present, only if the data is not
present in operands.
_NAME - Contains the name of object. This header is optional.
NEW_SYS is for making an object any job can access. NEW is for making one only its own job can access ๐. If the object gets created, you get an OBJECT instruction back. If it doesn't, you get RSP with a non-zero basic return code ๐ค
The immediate data field is transparent to the protocol ๐ซง. The sender VM forms it, and it must contain whatever information the addressee VM needs to create the object. Data must not be sent in operands and in the extension header at the same time ๐ โโ๏ธ
The SESSION_ID field of the instruction cannot be zero โจ. A dynamic object must be created only in the context of a specific job, and it's always created on the VM the session is connected to ๐ป
Zero values for the version and realization of an object just mean the object doesn't have those values ๐
You can register an object's name at the same moment you create it. The name goes in the _NAME extension header ๐
Every object created by NEW and NEW_SYS must be explicitly deleted ๐๏ธ. The VM must automatically delete all dynamic objects that the task created and didn't delete, at the end of the task ๐งน
6.6.4.2. OBJECT
OBJECT ("The Object") is the positive response to NEW and NEW_SYS ๐. Its fields:
OPCODE = 210
OPR_LENGTH = 2
Operands:
4 octets: The number of object.
2 octets: The version of object.
2 octets: The realization of object.
6.6.4.3. DELETE
DELETE ("To delete the object") removes an object that was created by NEW or NEW_SYS ๐๏ธ. The fields:
OPCODE = 211
OPR_LENGTH = 1
Operands:
4 octets: number of object
An object can only be deleted from the job that created it ๐. RSP gets sent in reply to this instruction.
6.6.5. The Objects Identification ๐ชช
When an object is registered on the node, you can identify it by its name, which is 4 - 254 octets long ๐. Names use ASCII symbols. Later versions of the protocol may define other kinds of names ๐ฎ
A name identifies the object by its number and is a synonym for it ๐ซ. The names of all active objects in one task on the node must be unique. So all active objects in the number range I - III must have unique names across all tasks on the node ๐. The protocol lets you get an object's number from its name, and get its name from its number, which is so useful ๐คฉ
6.6.5.1 OBJ_SEEK โจ
Okay so OBJ_SEEK is the instruction you send when you know an object's name but need its number ๐. It's basically asking "hey, what's the number for the object called this?" ๐
OPCODE = 212
OPR_LENGTH = 0
The extension header:
_NAME - contains the name of object for search.
If the object turns up, the answer is an OBJECT instruction ๐. If it doesn't, you get back an RSP with a non-zero basic return code ๐ฅฒ.
OBJ_SEEK can be sent broadcast through UDP ๐ก. When it's sent that way, it's about the zero-session ๐ง. You can include a REQ_ID field so you can match up the answers ๐. In this case, only positive responses are supposed to be sent ๐ . The response can go back over UDP too ๐ฆ.
6.6.5.2 OBJ_GET_NAME ๐ธ
This one is the reverse, bestie ๐. OBJ_GET_NAME ("To get a name of the object") is for when you have the object's number and want its name back ๐.
OPCODE = 213
OPR_LENGTH = 1
Operands:
4 octets: number of object for getting
If the object is present, the answer is an OBJECT instruction with the extension header _NAME โจ. If it isn't there, you get an RSP with a non-zero basic return code ๐ญ.
7 Chains ๐ซถ
Okay this part is so satisfying, it's basically group chats but for instructions ๐ฌ. Instructions that get sent on one session connection can be bundled into a chain ๐. A chain is just a group of instructions that are related to each other ๐. You can have several chains going at the same time in one session ๐.
There are three types of chains ๐:
- The sequence.
- The transaction
- The fragmented instruction.
If an instruction is part of a chain, the flag CHN should be equal to 1 โ . The field CHAIN_NUMBER in the header holds the chain's number ๐ข. INSTR_NUMBER is the instruction's serial number inside the chain, starting from 0 ๐. The protocol takes care of numbering the chains ๐ง. In one session you can have up to 65533 chains going at once ๐. The chain numbers %x0000 and %xFFFF are reserved by the protocol, so don't touch them ๐ซ. One chain can hold up to 65535 instructions ๐ .
The instruction with serial number 0 has to carry an extension header that describes the chain ๐. Every chain type has its own starting extension header โจ.
_END_CHAIN is the "end of the chain" extension header ๐. It goes on the last instruction of any chain, no matter what type it is ๐. It looks like this:
HEAD_CODE = 6
HEAD_LENGTH = 0
HOB = 1
The number of the chain that just finished is in the CHAIN_NUMBER field of the header of the instruction this extension header is attached to ๐.
โ ๏ธ Heads up: instructions in chains can go over UDP only if the whole chain fits in one segment. No splitting it up across segments for UDP ๐ค.
7.1 Sequence ๐ฆ
A sequence is a chain where the instructions depend on each other ๐๐. The next instruction in a sequence can only run on the VM if the one before it already ran ๐ฅ๏ธ. If the current instruction can't be executed, then all the other instructions in that sequence, whether they've already been sent or are waiting to be sent, just get cancelled ๐ โโ๏ธ. Because of that, a computing control thread doesn't have to wait for the current instruction to finish positively. It can just send the next one right away ๐โโ๏ธ๐จ.
_BEGIN_SQ is the "To begin a sequence" extension header ๐ฌ. It goes on the first instruction of the sequence ๐ฅ:
HEAD_CODE = 3
HEAD_LENGTH = 0
HOB = 1
The new chain's number goes in the CHAIN_NUMBER field of the header of the instruction that carries this extension header ๐ข. INSTR_NUMBER has to be 0 ๐.
The VM is the one who starts a sequence ๐. A sequence doesn't have to know how long it'll be ahead of time ๐คทโโ๏ธ. It can finish whenever ๐. If you need to end a sequence but there's nothing left to send, you can generate a NOP instruction to do it ๐ง.
7.2 Transaction ๐ผ
A transaction is a chain that groups together instructions which might not be connected to each other at all ๐งฉ. All transaction instructions have to run together, all at once, or not run at all ๐ค. You can cancel a transaction or confirm that it should execute โ . Cancelling a transaction after it has run isn't covered here ๐ โโ๏ธ. If you need that, the VM level should build that mechanism itself ๐ ๏ธ. That's because some instructions in a transaction can't be cancelled, like a control transfer ๐ซ.
The VM starts the transaction ๐. The transaction's length has to be known beforehand ๐. The length decides how the transaction gets transferred ๐. This is linked to the buffering described in section 7.4 ๐ง .
7.2.1 _BEGIN_TR ๐
_BEGIN_TR, the "To begin a transaction" extension header, is sent on the first instruction of the transaction ๐ฅ. It looks like this:
HEAD_CODE = 4
HEAD_LENGTH = 1
HOB = 1
DATA - Has the following format:
+---+---+---+---+---+---+---+---+
|TRE|TRR|TRS| Reserve |
+---+---+---+---+---+---+---+---+
| TIME_TR |
+---+---+---+---+---+---+---+---+
TRE (1 bit) is the flag for obligatory execution ๐ช. It only applies to a transaction that has been fully transferred but not yet executed ๐ฆ. If TRE = 1, the transaction must be executed when its lifetime (set by TIME_TR) runs out, or when the emergency session ends ๐จ. If TRE = 0, then when the lifetime runs out the transaction must be cancelled and a negative acknowledgement must be sent ๐ โโ๏ธ. If the emergency session ends, it just gets quietly cancelled ๐ซ .
TRR (1 bit) is the flag for executing after sending ๐. If TRR = 1, the transaction has to run after all its instructions have been sent, all at once ๐ฏ. This kind of transaction gets executed once the instruction with the _END_CHAIN extension header is received ๐. If TRR = 0, you need to send the special EXEC_TR instruction to acknowledge the transaction and get it to run ๐จ.
TRT (1 bit) is the flag for special processing ๐ฎ. It's there so the protocol can be expanded later ๐ฑ. If TRT = 1, some extra actions need to happen before the transaction runs, on top of the instructions in it, like deciphering for example ๐. Those actions could be defined in extra extension headers sent along with the transaction instructions ๐. This document doesn't define any cases where this flag gets used ๐. The value of TRT must be zero 0๏ธโฃ.
Reserve must be set to 0 ๐ง.
TIME_TR is 1 octet and it's the transaction's lifetime in 2-second intervals ๐. The maximal lifetime is 8 minutes โณ. The receiving side starts counting down this time after it has received all the transaction instructions โฑ๏ธ. The value %x00 means the transaction has no restriction on its lifetime โพ๏ธ.
The _END_CHAIN header is always sent in the last instruction of a transaction ๐.
7.2.2 EXEC_TR ๐
EXEC_TR ("To execute the transaction") is sent to get a transaction that was transferred earlier to run โถ๏ธ. Here are its field values:
OPCODE = 158
ASK = 1
PCK = %b01/10/11
CHN = 1
EXT = 0/1
CHAIN_NUMBER - Contains the number of chain, which is necessary to
execute.
INSTR_NUMBER = 0
OPR_LENGTH = 0
7.2.3 CANCEL_TR ๐ โโ๏ธ
CANCEL_TR ("To cancel transaction") is sent to cancel a transaction that was sent before and is supposed to run ๐. Here are its field values:
OPCODE = 159
ASK = 0
PCK = %b01/10/11
CHN = 1
EXT = 0/1
CHAIN_NUMBER - Contains the number of chain, which is necessary to
cancel.
INSTR_NUMBER = 0
OPR_LENGTH = 0
The instructions that make up a cancelled transaction get deleted, and there's no way to get them back ๐๏ธ๐.
7.3 Fragmented instruction ๐งฉ
UMSP is built to work with a transport protocol that has a limited size for each data segment ๐ฆ. An instruction gets fragmented in these two cases ๐ช:
- If the instruction is longer than the maximal segment size of the transport layer, or,
- If the segment is made up of several instructions and the last instruction doesn't fit in it completely.
The decision to fragment is made at the UMSP level ๐.
A fragmented instruction gets wrapped up in several NOP instructions ๐. All of those NOP instructions are then sent together as one chain of a special type ๐. Here's the algorithm used for the encapsulation ๐ง :
- The fields SESSION_ID and REQ_ID from the fragmented instruction are written into the first NOP instruction. If REQ_ID isn't present in the original instruction, it must not be in the NOP instruction. SESSION_ID is always present in fragmented instructions ๐.
- Next, those fields are deleted from the original instruction. The value of all the other header fields stays the same ๐ซถ.
- Then the original instruction is split into fragments of the necessary length ๐ช. Each fragment goes into an operand field of a NOP instruction. No other data should go into the operand field ๐ โโ๏ธ.
_BEGIN_FRG is the "The first fragment" extension header ๐ฅ. It goes on the NOP instruction that holds the first fragment. Its field values are:
HEAD_CODE = 5
HEAD_LENGTH = 0/2 ; Depends on subordination of the chain.
HOB = 1
Data:
2 octets: Number of the parental chain. Fragmented instruction
may be a part of the sequence or transaction.
2 octets: The instruction number in the parental chain.
The _END_CHAIN header goes on the NOP instruction that holds the last fragment ๐โจ.
7.4 Buffering โจ
okay so this part is all about the buffering the protocol uses when it receives data ๐ซถ (sending-side buffering is out of scope, so we're skipping that drama). ๐ง
If an instruction isn't in a chain, it goes straight to the VM for execution, so there's no buffering at the protocol level at all ๐ The interface between UMSP and the VM must provide asynchronous instruction sending. It is recommended that UMSP systems be fast enough to process the instructions they accept from the network at the same speed they were received ๐ฅ All instructions are designed to carry out known and limited computing load, with one exception: control transfer instructions, which must be processed in two stages. First the instruction's correctness is checked and its scheduling is made, and then the instruction is executed. The protocol must be able to get enough processor time to work in stationary mode ๐ So node overload questions get handled at the VM layer and the user application layer, where they can be sensibly controlled. Main character energy for those layers, honestly ๐ญ
For chains, the protocol gives you two buffering schemes during receiving ๐ฆ
- At session connection establishment, the two sides agree on the allocated buffer size, called the "window" ๐ The window is always bigger than the maximal segment of the transport layer. The transmitting side can use this buffer without coordinating with the receiving side first. The window size is set once for each session connection and can't be changed later. UMSP is built to work with a transport layer that tells you when data is delivered, so the transmitting side tracks the current free size of the receiving side's window for each connection on its own, no help needed โจ If the receiving side finds out it got data that can't fit in the window, the connection is broken off ๐
- For transactions and fragmented instructions whose size is bigger than the window, the sending side has to request permission to send from the receiving node ๐ The theoretical maximum size for a chain sent this way is 4 Gbytes ๐
REQ_BUF. The "To request the buffer" instruction asks the VM to allocate a buffer for sending a transaction or a large fragmented instruction (the "Window") ๐ It has these field values:
OPCODE = 24
ASK = 1
PCK = b01/11
CHN = 0
EXT = 0/1
OPR_LENGTH = 1
Operands:
4 octets: The buffer required size in octets. The value is
equal to the total size of all instructions of the
chain, including the size of the subordinated chains.
The protocol forms this instruction on its own initiative, and it uses RSP_P as the acknowledgement ๐ But the buffer actually gets allocated on the receiving side at the VM level, since the VM has the most complete info about the task. The interface between UMSP and the VM must allow asynchronous requests for this buffer ๐ง
REQ_BUF can be used whether or not the chain fits in the buffer allocated for the session (the window) ๐ Just know that a negative acknowledgement can come back on this instruction, while using a "window" guarantees sending โจ
A subordinated chain uses the buffer of its parent chain on the receiving side ๐
Sequence sending doesn't need a buffer allocation, unlike transactions or fragmented instructions ๐ธ If a single TCP connection is used for sending, sequences don't need buffering. But if multiple TCP connections with multiplexing are used, the sequence needs buffering for out-of-order instructions, and in that case it has to use the buffer allocated for the session ๐ญ
Transactions with the flag TRR = 0 must always request permission to send with REQ_BUF, even if they could fit in a single transport layer segment ๐
Buffering for fragmented instructions and for transactions with TRR = 1 depends on their size:
- If the transaction sits in one transport layer segment, it's sent without buffering ๐ฆ
- If the chain's length is no more than the "window", it can be sent without requesting a window buffer allocation. So the place in the buffer has to be reserved before sending starts. Sending can't begin if there isn't enough room in the buffer. In that case you can either wait for the window to be deallocated, or use the REQ_BUF instruction to request a buffer allocation from the VM ๐
- If the length goes beyond the session window size, you have to use the REQ_BUF instruction ๐
7.5 Acknowledgement of chains โจ
The REQ_ID field in chains of any type is only set in the first instruction, and it applies to the whole chain ๐ All the following instructions, including the last one, don't contain REQ_ID ๐ง
The transport protocol used for sending chains must report the end of the data transfer ๐ซถ That's because the transmitting side needs to know how much room is free in the allocated session window on the receiving side ๐
If the chain uses the allocated VM buffer (the permission to send, REQ_BUF, was requested), or if the whole chain sits inside a single transport layer segment, the protocol on the transmitting side doesn't track an acknowledgement ๐
If a sequence is transmitted, the transmitting side learns how much buffer space is free on the receiving side from the transport layer delivery acknowledgement ๐ฆ That works because regulated sequence instructions are handed to the VM right after they're received, which frees the buffer right away ๐
Fragmented instructions and transactions aren't handed to the VM until they're completely accepted ๐ญ If the session window is in use, the occupied buffer places can be calculated from the transport layer sending acknowledgement. To track free places, you have to check the execution acknowledgement from the VM. Here's the algorithm for that ๐
- The REQ_ID value that the VM gave for sending the chain is saved, and the value set by the protocol is entered in its place ๐
- The new REQ_ID value is sent in the first instruction of the chain โจ
- The chain is fully collected in the session window on the receiving side. After linking, it's sent to the VM for execution. The chain can keep occupying space in the buffer while this happens ๐ฅ
- After execution, the VM tells the receiving side's protocol ๐ฆ
- The protocol frees the place in the allocated buffer ๐ซง
- Then the protocol forms and sends the chain acknowledgement RSP_P, instead of RSP as in other cases ๐
- The transmitting side's protocol corrects its count of free space in the receiving side's buffer after it gets RSP_P ๐ง
- Then the old REQ_ID value is restored, and the acknowledgement is sent to the VM ๐ธ
7.6 Base-displacement Addressing โจ
A memory base address for relative addressing can be set for instructions within one chain ๐ซถ That means you can use abbreviated memory address fields in the chain's instructions. Those abbreviated addresses work as a displacement from the base ๐
_SET_MBASE. The extension header "To set memory base" sets the base address value for the chain ๐ It has these field values:
HEAD_CODE = 7
HEAD_LENGTH = 2/4/8 ; Depends on address length.
HOB = 1
DATA contains:
4/8/16 octets: The base address.
The address length is 3 octets. The name goes in the last octets of the 4-octet data field, and the initial octet is set to 0 ๐ง Base-displacement addressing isn't used for nodes with 2-octet address length ๐
The memory base value for a sequence can change ๐ฆ The base must be set once in any instruction for all transaction instructions. Setting the transaction base again is a mistake, and it results in the transaction being refused ๐
8 Extension Headers ๐
This section describes the extension headers that aren't tied to a specific instruction โจ The specialized extension headers are described in their own sections of this document ๐
8.1 _ALIGNMENT ๐
The "Alignment" extension header (_ALIGNMENT) lets you make any extension header or operand field a multiple of 4 to 16 octets, in steps of two octets ๐ซถ The protocol doesn't set any rules for using this header, so you can use it however you want ๐ฆ It has these field values:
HEAD_CODE = 8
HEAD_LENGTH = 1-7 ; Depends on length of the data field.
HOB = 0
DATA contains:
2 - 14 octets: All octets of the field have the zero-value.
The protocol instruction format already aligns two-octet fields without any extra help ๐
8.2 _MSG ๐ฌ
The "The any message" extension header (_MSG) lets you send a text message in ASCII characters ๐ง Receivers can handle this header in any order they like ๐ซง The message can be written to a log file, shown on the console, or ignored ๐ It has these field values:
HEAD_CODE = 9
HEAD_LENGTH = 1 - 127 ; Depends on data length of field.
HOB = 0
DATA contains:
2 - 254 octets: The any text of the message.
An instruction can contain several _MSG headers ๐ธ
8.3 _NAME ๐ท๏ธ
The "The Name" extension header (_NAME) lets you specify a job name, an object name, or an object procedure name โจ It has these field values:
HEAD_CODE = 10
HEAD_LENGTH = 1 - 127 ; Depends on length of a field of data.
HOB = 0
DATA contains:
2 - 254 octets: The text of the name in symbols ASCII.
8.4 _DATA ๐ซ
The "The Data" extension header (_DATA) is used for transferring data in exchange instructions between VMs, when the data can't fit in the operands ๐ฅ It lets you transfer up to 4 Gbytes of data in one instruction ๐ It has these field values:
HEAD_CODE = 11
HEAD_LENGTH = 1 - 2 147 483 647 ; Depends on length of the data
field.
HOB = 1
DATA contains:
2 - 4 294 967 294 octets : Binary data in an any format.
8.5 _LIFE_TIME โณ
okay so _LIFE_TIME is the header that tells the receiving VM how long an instruction is allowed to stay alive. it's giving deadline ๐ and I'm obsessed. its layout looks like this:
HEAD_CODE = 12
HEAD_LENGTH = 1/2; Depending on length of data.
HOB = 1
DATA contains:
2/4 octets: The time in 1,024 milliseconds intervals.
the header lets you set a limit on how long the instruction can take to reach the addressee's VM. literally a time limit, bestie ๐ซถ
how the lifetime gets counted is kind of the best part, so pay attention ๐
- sending side: time spent waiting in a queue for the transport layer counts. the lifetime drops by the waiting time, measured up to the moment the transport layer package is formed ๐
- receiving side: the lifetime only matters for fragmented instructions. it drops by the time it took to assemble the instruction โจ for non-fragmented instructions this header gets ignored when received. but its value MUST be sent to VM ๐
- transport time: the time spent sending at the transport layer doesn't count ๐ฆ and for fragmented instructions, only the sending time of the first fragment is left out of the count
when the lifetime of an instruction tied to a sequence runs out, the sequence sending finishes ๐ and the _LIFE_TIME header MUST NOT be used for transactions sending ๐
if the instruction is fragmented, _LIFE_TIME only rides along in the NOP instruction that holds the first fragment ๐ง the header gets removed from the original fragmented instruction. if time runs out before the rest of the fragmented instruction has been sent, the leftover part of the instruction gets cleared ๐งน
the sender VM sets the instruction lifetime, and it MUST be sent together with the data to the addressee VM ๐ if the lifetime expires, the instruction gets rejected, and a negative response is sent back if ASK = 1. if ASK = 0, no response goes out ๐ โโ๏ธ
last thing: _LIFE_TIME MAY be used in multimedia systems and in real time systems ๐ฌ and the protocol MAY bump up the sending priority for data that's about to hit the end of its lifetime ๐ฅ main character energy for urgent data
9 Search of resources ๐
okay bestie, Virtual Machines are the identified resources of the protocol ๐ฅ๏ธโจ standardizing the VM isn't UMSP's job. what the protocol gives you is a transparent environment for moving code and data of any type. slay ๐
every VM connected to the protocol gets these two values:
- VM type: the range of values is 1 - 65534 ๐ธ
- VM version: the range of values is 1 - 65534 ๐ธ
the protocol REQUIRES backwards compatibility, bottom-up, for VMs of the same type with different version numbers. so a VM with a higher version number MUST be able to run VM code written for any lower version number ๐ซถ it's like how a new phone still opens your old apps ๐ฑ
VM type numbers are split into these ranges:
1 - 1023 Assigned for standard VM
1024 - 49151 Assigned for registered VM of the users
49152 - 65534 Free (defined for dynamic and/or private VM)
types and versions %x0000 and %xFFFF are reserved by the protocol ๐ซ hands off
now, groups ๐ several VMs of different types can join a group. every VM in the group MUST work in the shared local memory space and MUST have the same jobs-control subsystem. it also means that if the same 128-bit address shows up in any VM's code for one task, it MUST point at one physical memory cell ๐ง when those conditions are met, multivendor user code (with procedures for different VMs) can run on one node. every VM in the group MUST have a different type ๐จ a group can hold no more than 65534 VMs. one group number on different nodes MAY identify groups with different VM structures ๐
each group VM on a node gets a 2-octet group code ๐ข as long as the node has even one session connection, the group codes MUST NOT change. it is RECOMMENDED to change a group code only when the node is reconfigured ๐ ๏ธ a group VM gets identified just like a single VM. the type is set to 0, and the group number goes in the VM version field ๐
supporting VM association in groups is an OPTIONAL requirement of the protocol ๐ multivendor user code can still run without group association. the trick is that procedures containing different code types MUST run on different nodes ๐ง
UMSP gives you VM search instructions, which tell you exactly which VMs and VM groups are connected to the protocol on a given node at a given moment ๐
VM search instructions can be sent over TCP or UDP ๐จ broadcast dispatch is an option too. a node can notify about its VMs on its own (say, when it starts up) or reply to other VMs' requests ๐ข answer-back instructions MUST be sent over the same protocol the request came in on ๐
VMs in the number range 49152 - 65534, and any VM group, MAY be identified by name ๐ท๏ธ VMs numbered 1 - 49151 MUST NOT have names at the UMSP instruction layer ๐ โโ๏ธ
9.1 VM_REQ ๐
the "To request the VM" instruction (VM_REQ) lets you find out which VMs are connected on the remote node ๐ its fields look like this:
OPCODE = 25
PCK = %b00
CHN = 0
ASK = 0/1
EXT = 0/1
OPR_LENGTH = 0 - 65534 ; Depending on quantity VM in operands.
Operands:
2 octets: The type required VM. The value 0 is not allowed.
2 octets: The version required VM. The value 0 is not allowed.
The value %xFFFF requests the most senior version.
.
.
.
2 octets: The type required VM.
2 octets: The version required VM.
The optional extension header:
_NAME - This header contains the name of required VM or VM
group.
no operands means you're asking for every VM type connected on the node ๐ one VM in the operands gets you info on that one VM. several VMs in the operands means you're asking for a VM group that contains all of them ๐ the type and version pairs in the list MUST be indexed in increasing order ๐
if you're using VM_REQ without a session connection, the VM type and version MUST have the value %xFFFF ๐
the _NAME header isn't tied to the operand values ๐ญ it needs its own separate answer, which MUST be sent back ๐ฌ
9.2 VM_NOTIF ๐ฃ
the "To notify about VM" instruction (VM_NOTIF) is how you announce one VM or one VM group attached to the node ๐ฃ its fields look like this:
OPCODE = 26
PCK = %b00
CHN = 0
ASK = 0/1
EXT = 0/1
OPR_LENGTH = 1 - 65534 ; Depending on quantity VM in operands.
Operands:
2 octets: The used transport protocol. The following values of
this field are definite:
x0100 - Single TCP connection through the port 2110.
x0101 - Multiple TCP connection through the port 2110.
x0102 - Single TCP connection through ports 2110 and UDP
through ports on receiving 2110.
x0103 - Multiple TCP connection through ports 2110 and UDP
through port on receiving 2110.
the port 2110 MUST be opened on one side or both sides for each TCP connection ๐
2 octets: Reserved.
2 octets: The type VM.
2 octets: The version VM.
.
.
.
2 octets: The type VM.
2 octets: The version VM.
The optional extension header:
_NAME - This header contains the name by separate VM or group VM
from operands of the instruction.
about that Reserved field: the protocol MUST NOT analyze it when receiving in the current realization of the protocol ๐ and when sending, it MUST be set to 0 ๐งผ
if you need to tell someone about several VMs or groups, you generate several instructions ๐ and if the node provides several transport protocols, you form a separate instruction for each protocol ๐
if the instruction is answering a VM_REQ request, it can have ASK = 1 and a REQ_ID whose value comes from the request instruction ๐ฏ if the VM group was requested, the instruction MUST contain several VMs. the first VM MUST have its type set to 0, and its version MUST hold the group number ๐ the other VMs MUST define the group structure ๐งฉ the type and version pairs in the VM list MUST be indexed in increasing order ๐
the protocols listed in a VM_NOTIF instruction MAY be different from the protocol the instruction itself travels over ๐ฆ
10 Security Considerations ๐โจ
okay bestie, this section is the serious one ๐ญ The whole doc only has the bare-bones stuff needed to get immediate access to memory on a remote node going. To keep the protocol from being too complicated at first, the safety questions are NOT in this document. Everything in this unit is basically a recommendation for expanding the protocol later ๐ธ
For the description, there are three nodes. Node A and node B are the ones exchanging data, and node G is JCP ๐
Protection against sniffing, spoofing and hijacking:
- The means specified in TCP/IP can be used. ๐ก๏ธ
- There is a possibility to create chains with special processing ๐ฆ To make one of these chains, you have to send the extension header that sets the special processing in the first instruction of the chain. The instructions in the chain can be encapsulated in NOP instructions. Algorithms that check instruction sequence integrity, or do encryption, can be built this way ๐
Protection against the man-in-the-middle:
The protection is based on the fact that the routes between nodes A - B, A - G and G - B are not crossed ๐ง This setup lets you run an extra managing dataflow, which helps reveal this type of attack. But if those specified routes all go through one gateway, the protection is way less effective ๐ฌ
Authentication:
The protocol is built on centralized control, and it supports several authentication schemes ๐ The authentication parameters are sent in the extension headers. Setting up a session connection can include up to eight handshakes. This also gives you more flexibility when you choose an authentication algorithm. Authentication can happen between all three node pairs: A - B, A - G and G - B. Every pair can be used in any combination, and node G can be specially set aside just for doing authentication ๐
Protection against denial-of-service:
The protocol's instructions have set computing loads. This means you can design the node so it processes instructions as fast as they arrive from the network โก A likely cause of overload is the JUMP and CALL instructions ๐ VM has to handle this problem. It has complete information about the user task, so it can decide how many resources to allocate ๐ The fix for a problem is dropping service for low-priority traffic. Literally a sacrifice, but it works ๐
Protection at the applications architecture level:
The protocol lets you build applications with any architecture you want ๐ That's possible because the connection structure is asymmetric. There are three basic groups:
- The client carrying out terminal functions, plus client/server technologies. Security in these systems is completely defined by the server, and this architecture is considered the most protected ๐ก๏ธ
- The client loading active code from the server. This is the least protected architecture from the client's point of view. On the server side, there are no special requirements for protection ๐ซ
- The client executing its code on the server. This architecture is safe for the client, but the server's protection needs to be strengthened ๐ช Its functionality doesn't differ from the architecture where the client loads active code. If you take into account that the server is a specially allocated computer, this architecture is optimum โจ
All of these technologies may be used at the same time, in any combination ๐
11 Used Abbreviations ๐
- API: Application Programming Interface. ๐งฉ
- CTID: JCP assigns the Control Task IDentifier to each task of the job. Its length is equal to the length of the local address memory on the node JCP. ๐ซ
- GJID: Globally Job IDentifier is assigned for each job. GJID is defined on the JCP node. It has the same format as the 128 - bit address of node JCP memory has. The address of local memory is replaced by the CTID of the first (initial) task of the job in it. ๐
- GTID: Globally Task IDentifier is assigned to each task. GTID has the same format as the 128 - bit address of node memory has. The address of local memory is replaced by the LTID in it. ๐ชช
- JCP: Job Control Point. This node controls the job. ๐
- LTID: Locally Task IDentifier is assigned to each active task on the node. LTID length is equal to the local memory address length defined for the node. ๐ง
- VM: Virtual Machine. ๐ป
12 References ๐
[1] Bradner, S., "The Internet Standards Process -- Revision 3", BCP 9, RFC 2026, October 1996.
[2] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", RFC 2119, March 1997.
[3] Crocker, D., and P. Overell. "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, November 1997.
[4] Postel, J., "Transmission Control Protocol - DARPA Internet Program Protocol Specification", STD 7, RFC 793, September 1981.
[5] Postel, J., "User Datagram Protocol", STD 6, RFC 768, August 1980.
[6] Srinivasan, R., "RPC: Remote Procedure Call Protocol Specification Version 2", RFC 1831, August 1995.
13 Author's Address ๐๏ธ
Alexander Y. Bogdanov
NKO "ORS"
22, Smolnaya St.
Moscow, Russia 125445
RU
Phone: +7 901 732 9760
EMail: a_bogdanov@iname.ru
14 Full Copyright Statement โ๏ธ
Copyright (C) The Internet Society (2000). All Rights Reserved.
This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself may not be modified in any way, such as by removing the copyright notice or references to the Internet Society or other Internet organizations, except as needed for the purpose of developing Internet standards in which case the procedures for copyrights defined in the Internet Standards process must be followed, or as required to translate it into languages other than English.
The limited permissions granted above are perpetual and will not be revoked by the Internet Society or its successors or assigns.
This document and the information contained herein is provided on an "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Acknowledgement ๐ท
Funding for the RFC Editor function is currently provided by the Internet Society. ๐
๐ฆ where this page comes from
- ietf: rfc3018 2000-12
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms