Contents
1 Fundamental concepts
1.1 Om compliance level 1
The core object model required and enforced by OOMPH is Om compliance level 1.
At this level, Om deals with two separate kinds of entity: objects, and atoms. Objects are fully opaque, supporting only one operation (messages). Atoms are simpler things, like integers or strings, but one possible kind of atom is a reference to an object.
Objects support a number of messages. Each message takes only three pieces of information: a selector (usually a string, but any atom may be a selector), a recipient (a reference to an object), and a sender (also a reference, although optional). Messages may fail for a number of reasons (object doesn't support that message, lack of authorization, etc.); if they succeed, they result in a new Om process. A process may run quickly, or over some time. It has some associated state: whether it's currently running, not yet started, or finished, and whether it has an exception condition.
While a process is running, data can be passed in and out of it, as a pack of atoms. Some process may do this only once, others may allow multiple “communications” in and out.
1.2 Sites, hosts, and ports
A host is an “universe” as far as Om is concerned; a set of objects, the relationships between them, the rules governing operation, the set of available interfaces and facades, and so on. Objects on different hosts can only communicate via some inter-host communication system, such as OOMPH. A host may correspond concretely to an “Om daemon session”, or an Om-compatible but not Om-based application, for example.
An Om/OOMPH site is a set of related objects; generally, all objects “local” to a host, although in certain cases a host may contain many sites. In particular, some special sites are meant to be replicated in many (or all) hosts; a very special case is “the Om site” (site id 0), which contains objects representing the Om specification and libraries.
Objects are identified by a pair of (site id, object id). The object id is unique inside its site, but local to the site. If hosts A and B are communicating, and A refers to and object (x, y), and B happens to have a copy of the same object (site x and object id y), B may use its own copy. (Again, this situation is likely to happen with site 0.)
Finally, a port is one of the objects through which Om hosts communicate when using OOMPH. Each host creates a port object, binding it to one (or more) lower-level communication system such as TCP/IP sockets, and the port objects “talk” to each other. A port is an object, and as such has an interface which the other port can communicate with. For that purpose, it's conventioned that the object (0, 0) will be reserved, essentially meaning “I” or “you” (depending on the “local” bit); in the case of OOMPH, that means the sending and receiving port objects.
1.3 Interfaces and selectors
A selector is the “name” of a message being sent over the port. It's usually a string with the actual message name, but the PortOptimizer interface can “translate” it to numeric IDs for quicker over-the-wire communication. Depending on the implementation of each host, the special “null selector” may also be supported (the special singleton atom “nothing”). In Om compliance level 2, for example, that represents “executing” objects themselves.
As a very special case, the port object accepts “named” atoms as selectors. A named selector is a shortcut for sending a message to a specific interface of the port object (as opposed to casting, which is only possible on ports which implement Om compliance level 2, and then sending a normal message). In this case, the “name” atom is taken as the interface, and the “data” atom is interpreted as a selector according to the usual rules.
2 Packets
All communication happens in packets. The first four bytes of a packet represent the “packet signature”; the most significant octet contains the “packet type”, and the remainder, the packet length in octets. These four octets are not counted toward the packet length.
Note that this allows a maximum packet size of 16MiB. Frankly, that should be enough for the quite a few years, but a new major version of the protocol can be introduced when it isn't. In the rare case that a packet does need to transmit more than 16MiB, continuation packets can be used. (But data large enough to need it should probably be sent out-of-band.)
The following packet types are defined in this version of the protocol:
2.1 Negotiation packet
Type number: 0
These packets are generally sent immediately after the connection is established, so that both ports can know each other's level of support. But the protocol allows negotiation packets at any time, even changing settings already agreed upon. This way, a port can change its features on the fly (possibly by loading or unloading plug-ins, for example).
Negotiation packets always follow this form: first, a zero-terminated ascii string, with the item name. Then, for the remaining of the packet, the item data.
2.1.1 Protocol handshaking
The first packet in every connection, in both directions, should always be (in bytes): \0 \0 \0 \9 O O M P H V \0 b \1. This is interpreted as “My protocol version is b1”. Since the three most significant bytes of the packet header will always be 0, this also doubles as a negotiation of endianess. The protocol explicitly allows both sides to operate in different endianess. However, a special packet of \0 \0 \0 \0 after endianess handshaking should be interpreted as a request for both ends to operate on the sender's byte order; generally, this feature should rarely be used, but it can provide a very minor optimization for embedded platforms. If both sides send this special packet, then both should ignore it and use the endianess information they had already negotiated previously.
Two ports operating on the same major version (as of this writing, “b”) should be compatible. Differences in minor version (as of this writing, “1”) can be resolved via feature negotiation and the libraries on each end. In order for that to work, the port with the higher version should emulate the version understood by the other port. If major versions differ, it's up to the port with the higher version to choose to emulate another version (with the same major number as the other port), by sending a new handshaking packet, or to emit a negotiation error packet and close the connection.
2.1.2 Atom types negotiation
This packet maps atom type codes to well-known names. It should always be sent from the server to the client. The item name is “ATOMTYPES”. The item data is a sequence of type definitions. Each definition consists of: one single byte with the type code, then a X-bit site id, and a zero-terminated ascii string with the well-known type name.
The client should respond with a negotiation packet with item name “ATOMTYPESOK”, containing only the type codes of atom types it recognizes. The server must refrain from using atom types not in that list. If the server finds it impossible to operate using only those types, it should emit a negotiation error packet and close the connection.
Types defined by this spec all have a site id of 0, meaning the special site which corresponds to the Om/OOMPH specs. These are the only types an implementation is required to support. Extension types (with non-zero site ids) are left for implementations to extend and optimize the protocol. In addition, embedded implementation are allowed to support only a subset of spec types: they may omit string encodings, as long as at least one non-ascii encoding is supported, and they may omit number formats, as long as the widest signed and unsigned integer and floating point types are supported.
2.1.3 Feature negotiation
This packet negotiates protocol/runtime features. The item name is “FEATURES”, and the item data is a sequence of feature names. Each feature name consists of a X-bit site id, then a zero-terminated ascii string with the well-known feature name.
The client should respond with a negotiation packet with item name “FEATURESOK”, containing a new sequence of feature names in the same format, which the client supports. This list must be a subset of the list sent by the server on “FEATURES”. If the server finds it impossible to operate using only those features (or if the returned list is not a subset of the sent list), it should emit a negotiation error packet and close the connection.
Features defined by this spec all have a site id of 0, meaning the special site which corresponds to the Om/OOMPH specs. Extension features (with non-zero site ids) are left for implementations to extend and optimize the protocol.
Those features are defined in this spec:
- exceptiondetail
- Error conditions get their “details” field set with a reference to a details object. (See Status Update packet.)
- compriorities
- Communications have a “priority” field.
- comsupersede
- Communications can supersede other communications.
- multicommin
- A requester can communicate to a process more than once.
- multicommout
- A process can communicate to its requester more than once.
- quickmsg
- The Quick Call packet type and associated semantics.
- receipts
- Communications can request receipts.
- errormsg
- Fail packets may contain error message strings.
- oob
- Communications can be sent using out-of-band channels. (To be specced.)
- tobj
- Transient objects can be sent as atoms. (To actually use those objects with Om semantics, compliance level 2 is required; see the Om spec for more details.)
2.1.4 Interface negotiation
This packet negotiates port features. The item name is “INTERFACES”, and the item data is a sequence of interface names. Each interface name consists of a X-bit site id, then a zero-terminated ascii string with the well-known feature name.
Different from features and atom types, this packet is not asymmetric (sent from server to client); both sides should send it, in no particular order, since each port may implement a different set of interfaces.
Features defined by this spec all have a site id of 0, meaning the special site which corresponds to the Om/OOMPH specs. Extension features (with non-zero site ids) are left for implementations to extend and optimize the protocol.
The very first interface is the one the port is implementing by default; it should always be PortLevel1 or a compatible (derived, in terms of Om compliance level 3) interface.
See the Port interfaces section for mode details.
2.1.5 Negotiation error
This packet has the item name “NOCANDO”. Item data is optional, and if present, is an ascii string with a message that can be logged or displayed to the user on the other side. A port may close the connection immediately after sending this packet, in case the error was fatal; if the connection is left open, the error is interpreted as non-fatal, and the other side should attempt to address the situation by re-negotiating.
2.2 Message packet
Type number: 1
An Ok or Fail packet should be sent back immediately.
2.3 Comm In packet
Type number: 2
2.5 Status Update packet
Type number: 4
Packet may omit error type, message, and details if there is no error. Details must be omitted if exceptiondetail feature is disabled, and may be omitted if there isn't a details object (equivalent to sending nothing).
Sending unknown as the error type/details means existing error information should be preserved.
2.7 Fail packet
Type number: 6
2.8 Quick Call packet
Type number: 7
Same semantics of Message, but the other side will only send back the first Data Out, and the first Status Update that sets state to inactive. Superseding and priority is considered disabled for that process (if priorities are on, that message will be treated as highest priority).
2.9 Error packet
Type number: 8
This represents a more general protocol error. The error codes aren't meant to correspond to HTTP errors, but the “hundreds” category system from HTTP is reused.
- 400 and 401: no such process
- A communication or status update was sent to an unknown process. The id field is a pack id if this error is referring to a communication that had an id (error code is 401), and a process id otherwise (error code is 400).
- 402 and 403: process is dead
- A “comm in” packet was sent to a process which is already inactive. The id field is as above; 402 corresponds to 400, and 403 to 401.
- 404: no such object
- An object referred to (possibly in a reference atom) doesn't exist.
- 405: bad packet
- The packet was somehow malformed (wrong number or type of arguments, for example). The id field is unused.
- 406: unknown packet
- A packet was sent with an unknown packet type number. The id field is that type number.
- 407: unknown interned
- An interned atom was sent but isn't in the port's registry.
2.10 Done packet
Type number: 9
Tells the other port we're no longer interested in a (remote) process. The receiving port shouldn't send any more status updates or communications originating from this process. If the process goes inactive and there are no ports interested in it, the process information may be deleted.
2.11 Release packet
Type number: 10
Tells the other port we're no longer interested in a (remote) object. That may be interesting if the remote object was “transient”, with references held only by the remote port (such as those returned from casts).
2.12 Continuation packet
Type number: 255
Packets with this type number should be considered a continuation of the preceding packet.
3 Atoms
3.1 Defined atom types
These atom types are defined in this version of the spec.
- nothing, unknown
- Special atoms, zero-length.
- nan, inf, neginf
- Special numbers, zero-length.
- int8, int16, int32, int64, uint8, uint16, uint32, uint64
- Integers, signed or unsigned, of the corresponding bit lengths.
- dec8, dec16, dec32, dec64, udec8, udec16, udec32, udec64
- Decimals, signed or unsigned, of the corresponding bit lengths. Note the actual atom will have twice the length specified; the first n bits will be the integral part, and the next n will be the fractional part, considering the maximum width fully representable by the bit length; so a dec8 \2 \5 is actually 2.05. Widths are: 2 for 8 bits, 4 for 16 bits, 9 for 32 bits, 19 for 64 bits.
- float16, float32, float64, float128, ufloat16, ufloat32, ufloat64, ufloat128
- Floating-point numbers, signed or unsigned, of the corresponding bit lengths.
- stra, stru8, stru16, stru32
- Strings, respectively encoded as ascii, utf-8, utf-16, and utf-32. In all cases, the first two octets should be read as a 16-bit unsigned integer; they represent the length of the string, in octets (not characters).
- str0
- Strings, encoded as ascii and zero-terminated. This should be used only for small, ascii data, such as symbols.
- bytes
- A sequence of uninterpreted bytes (probably meant for interpreting by high-level code, such as image data). The first four octets form an unsigned 32-bit length marker.
- ref
- A 32-bit reference to an object. The highest (most significant) bit is set if the object is on the sender host, and unset if the object is on the receiver.
- fullref
- A X-bit reference to an object, with the first X bits being a site id, and the next 32 being an object ref (same as “ref” above, but the most significant bit is ignored).
- siteref
- A X-bit site id.
- tobj
- A packed transient object. The next two octets should be read as an unsigned integer with the number of attributes n. Then follows a sequence of n pairs of atoms; in each pair, the first atom should be a string, and is interpreted as the attribute name, with the second one being the attribute value.
- named
- A pair of atoms. The first must be a string type, and is taken as the name of the data in the second atom. (If interned atoms and PortOptimizers are in use, the first atom may also be an “interned” which points to a string.)
- sequence
- A sequence of atoms, with no implied semantics. The first 16 bits are an unsigned integer with the number of items.
- interned
- A 16-bit opaque ID representing an “interned” atom, registered with the PortOptimizer interface. The most significant bit is 1 if the atom was interned on the sender port, and 0 if it was interned on the recipient port.
4 Port interfaces
4.1 PortLevel1
OOMPH port, Om compliance level 1. This interface has messages which provide basic object manipulation according to Om compliance level 1. (To be specced.)
4.2 PortLevel2
OOMPH port, Om compliance level 2. This interface has messages which provide basic object manipulation according to Om compliance level 2. A PortLevel2 can be used as a PortLevel1 (in terms of Om compliance level 3, it's a derived interface). The methods listed below are in addition to those of PortLevel1. (To be specced.)
4.3 ObjectPathResolver
Om object path resolver. This interface has messages which allow you to get references to objects by an opaque path (similar to how URIs/URLs work). (To be specced.)
4.4 InterfaceRegistryLevel2
Om interface registry, compliance level 2. This interface has messages which allow you to query simple information about interfaces, including synonym relationships and canonical names. (To be specced.)
4.5 InterfaceRegistryLevel3
Om interface registry, compliance level 3. This interface has messages which allow you to deal with Interface objects, including retrieving them by name. An InterfaceRegistryLevel3 can be used as a InterfaceRegistryLevel2 (in terms of Om compliance level 3, it's a derived interface). The methods listed below are in addition to those of InterfaceRegistryLevel2. (To be specced.)
4.6 ServiceManager
Om service manager. This interface has messages which allow you to request special Om objects called “services”. (To be specced.)
4.7 PortOptimizer
Om port optimizer. This interface has messages which allow you to “intern” atoms, receiving a numeric id that can be used in substitution of the original atom in any situation. (To be specced.)
4.8 DublinCore
Dublin Core metadata. This interface has messages which allow you to query simple information about the host the port is attached to. (To be specced.)