RFC 3018

Unified Memory Space Protocol Specification

๐Ÿ“… published December 2000, from ietf

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 (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 ๐Ÿ’…

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:

  1. Job
  2. Task
  3. 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:

  1. if the operands length has to be more than 24 octets
  2. 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:

  1. The management instructions transmitted on UMSP layer (OPCODE = 1 - 112).
  2. 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:

  1. 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.
  2. 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:

  1. A task with the received GTID is already registered on JCP.
  2. 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 ๐Ÿ‘‘

  1. 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 โœจ.
  2. 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:

  1. Remove all session connections connected to the task. It isn't necessary to send network primitives for this.
  2. 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:

  1. 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.
  2. 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:

  1. 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.
  2. 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:

  1. 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.
  2. TASK_REJECT, if the time since TASK_REG doesn't fit for the JCP.
  3. 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:

  1. Send STATE_REQ to all tasks on the node that were initiated before the penultimate STATE_REQ instruction was sent.
  2. Wait for one inaction interval to end after the last STATE_REQ instruction was sent (the one that got the negative response).
  3. 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 ๐Ÿ”ช:

  1. If the instruction is longer than the maximal segment size of the transport layer, or,
  2. 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 ๐Ÿง :

  1. 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 ๐Ÿ’–.
  2. Next, those fields are deleted from the original instruction. The value of all the other header fields stays the same ๐Ÿซถ.
  3. 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 ๐Ÿฆ‹

  1. 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 ๐Ÿ’€
  2. 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:

  1. The means specified in TCP/IP can be used. ๐Ÿ›ก๏ธ
  2. 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:

  1. 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 ๐Ÿ›ก๏ธ
  2. 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 ๐Ÿซ 
  3. 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

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