mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-01 02:41:48 +00:00
Add protocol specification documentation.
These have been converted to asciidoc (asciidoctor variant) from the original Google Docs documents.
This commit is contained in:
198
doc/alloy-model.adoc
Normal file
198
doc/alloy-model.adoc
Normal file
@@ -0,0 +1,198 @@
|
||||
= Network Tables Alloy Model
|
||||
|
||||
Alloy (http://alloy.mit.edu/alloy/) is a formal logic tool that can analyze
|
||||
first-order logic expressions. Under the proposed sequence number -based
|
||||
protocol, assuming that all nodes start from the same state, Alloy is unable to
|
||||
find a way where two nodes with the same sequence number have different state
|
||||
when activity ceases.
|
||||
|
||||
The model used is included below. Although Alloy cannot test all cases, since
|
||||
such an exhaustive search is intractable, it provides a high level of
|
||||
confidence in the proposed protocol.
|
||||
|
||||
----
|
||||
--- Models a distributed, centralized hash table system called NetworkTables
|
||||
--- System state is protected by sequence numbers; the server's value for a certain sequence number always wins
|
||||
--- Paul Malmsten, 2012 pmalmsten@gmail.com
|
||||
|
||||
open util/ordering[Time] as TO
|
||||
open util/natural as natural
|
||||
|
||||
sig Time {}
|
||||
sig State {}
|
||||
|
||||
--- Define nodes and server
|
||||
sig Node {
|
||||
state: State -> Time,
|
||||
sequenceNumber: Natural -> Time
|
||||
}
|
||||
|
||||
--- Only one server
|
||||
one sig Server extends Node {
|
||||
}
|
||||
|
||||
--- Define possible events
|
||||
abstract sig Event {
|
||||
pre,post: Time,
|
||||
receiver: one Node
|
||||
}
|
||||
|
||||
// For all events, event.post is the time directly following event.pre
|
||||
fact {
|
||||
all e:Event {
|
||||
e.post = e.pre.next
|
||||
}
|
||||
}
|
||||
|
||||
// Represents that state has changed on a node
|
||||
sig StateChangeEvent extends Event {
|
||||
}
|
||||
|
||||
// Represents that state has been transferred from one node to another
|
||||
sig StateTransferEvent extends Event {
|
||||
sender: one Node
|
||||
}
|
||||
|
||||
fact {
|
||||
--- Every node must assume at most one state
|
||||
all t:Time, n:Node | #n.state.t = 1
|
||||
|
||||
--- Every node must assume one sequence number
|
||||
all t:Time, n:Node | #n.sequenceNumber.t = 1
|
||||
|
||||
--- Sequence numbers may only increment
|
||||
all t:Time - last, n:Node | let t' = t.next | natural/gte[n.sequenceNumber.t', n.sequenceNumber.t]
|
||||
}
|
||||
|
||||
|
||||
fact stateChangedImpliesAStateTransfer {
|
||||
all sce:StateChangeEvent {
|
||||
// A StateChange on a client causes a transfer to the Server if its sequence number is greater than the server's
|
||||
sce.receiver in Node - Server and natural/gt[sce.receiver.sequenceNumber.(sce.post), Server.sequenceNumber.(sce.post)]
|
||||
implies
|
||||
some ste:StateTransferEvent {
|
||||
ste.pre = sce.post and ste.sender = sce.receiver and ste.receiver = Server
|
||||
}
|
||||
}
|
||||
|
||||
all sce:StateChangeEvent {
|
||||
// A StateChange on the server causes a transfer to all clients
|
||||
sce.receiver = Server implies
|
||||
all n:Node - Server {
|
||||
some ste:StateTransferEvent {
|
||||
ste.pre = sce.post and ste.sender = Server and ste.receiver = n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
all sce:StateTransferEvent {
|
||||
// A StateTransfer to the server causes a transfer to all clients
|
||||
sce.receiver = Server implies
|
||||
all n:Node - Server {
|
||||
some ste:StateTransferEvent {
|
||||
ste.pre = sce.post and ste.sender = Server and ste.receiver = n
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fact stateTransferEventsMoveState {
|
||||
all ste:StateTransferEvent {
|
||||
ste.sender = Server and not ste.receiver = Server or ste.receiver = Server and not ste.sender = Server
|
||||
|
||||
// Nodes can only post to the server if their sequence number is greater than the servers
|
||||
ste.receiver = Server implies natural/gt[ste.sender.sequenceNumber.(ste.pre), ste.receiver.sequenceNumber.(ste.pre)]
|
||||
|
||||
// Server can only post to clients if its sequence number is greater than or equal to the client
|
||||
ste.sender = Server implies natural/gte[ste.sender.sequenceNumber.(ste.pre), ste.receiver.sequenceNumber.(ste.pre)]
|
||||
|
||||
// Actual transfer
|
||||
(ste.receiver.state.(ste.post) = ste.sender.state.(ste.pre) and
|
||||
ste.receiver.sequenceNumber.(ste.post) = ste.sender.sequenceNumber.(ste.pre))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fact noEventsPendingAtEnd {
|
||||
no e:Event {
|
||||
e.pre = last
|
||||
}
|
||||
}
|
||||
|
||||
fact noDuplicateEvents {
|
||||
all e,e2:Event {
|
||||
// Two different events with the same receiver imply they occurred at different times
|
||||
e.receiver = e2.receiver and e != e2 implies e.pre != e2.pre
|
||||
}
|
||||
}
|
||||
|
||||
fact noStateTransfersToSelf {
|
||||
all ste:StateTransferEvent {
|
||||
ste.sender != ste.receiver
|
||||
}
|
||||
}
|
||||
|
||||
fact noDuplicateStateTransferEvents {
|
||||
all ste,ste2:StateTransferEvent {
|
||||
// Two state transfer events with the same nodes imply that they occurred at different times
|
||||
ste.sender = ste2.sender and ste.receiver = ste2.receiver and ste != ste2 implies ste.pre != ste2.pre
|
||||
}
|
||||
}
|
||||
|
||||
--- Trace (time invariant)
|
||||
fact trace {
|
||||
all t:Time - last | let t' = t.next {
|
||||
all n:Node {
|
||||
// A node in (pre.t).receiver means it is being pointed to by some event that will happen over the next time step
|
||||
n in (pre.t).receiver implies n.state.t' != n.state.t and n.sequenceNumber.t' != n.sequenceNumber.t // A node which receives some sort of event at time t causes it to change state
|
||||
else n.state.t' = n.state.t and n.sequenceNumber.t' = n.sequenceNumber.t // Otherwise, it does not change state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
--- Things we might like to be true, but are not always true
|
||||
|
||||
pred atLeastOneEvent {
|
||||
#Event >= 1
|
||||
}
|
||||
|
||||
pred allNodesStartAtSameStateAndSequenceNumber {
|
||||
all n,n2:Node {
|
||||
n.state.first = n2.state.first and n.sequenceNumber.first = n2.sequenceNumber.first
|
||||
}
|
||||
}
|
||||
|
||||
pred noStateChangeEventsAtEnd {
|
||||
no e:StateChangeEvent {
|
||||
e.post = last
|
||||
}
|
||||
}
|
||||
|
||||
--- Demonstration (Alloy will try to satisfy this)
|
||||
|
||||
pred show {
|
||||
atLeastOneEvent
|
||||
}
|
||||
run show
|
||||
|
||||
--- Assertions (Alloy will try to break these)
|
||||
|
||||
assert allNodesConsistentAtEnd {
|
||||
allNodesStartAtSameStateAndSequenceNumber implies
|
||||
all n,n2:Node {
|
||||
// At the end of a sequence (last) all nodes with the same sequence number have the same state
|
||||
n.sequenceNumber.last = n2.sequenceNumber.last implies n.state.last = n2.state.last
|
||||
}
|
||||
}
|
||||
check allNodesConsistentAtEnd for 3 Event, 10 Node, 3 State, 5 Time, 5 Natural
|
||||
check allNodesConsistentAtEnd for 8 Event, 2 Node, 5 State, 9 Time, 9 Natural
|
||||
|
||||
assert serverHasHighestSeqNumAtEnd {
|
||||
allNodesStartAtSameStateAndSequenceNumber implies
|
||||
all n:Node - Server{
|
||||
// At the end of a sequence (last) all nodes with the same sequence number have the same state
|
||||
natural/gte[Server.sequenceNumber.last, n.sequenceNumber.last]
|
||||
}
|
||||
}
|
||||
check serverHasHighestSeqNumAtEnd for 3 Event, 10 Node, 3 State, 5 Time, 5 Natural
|
||||
----
|
||||
454
doc/networktables2.adoc
Normal file
454
doc/networktables2.adoc
Normal file
@@ -0,0 +1,454 @@
|
||||
= Network Tables Protocol Specification, Version 2.0
|
||||
Protocol Revision 2.0 (0x0200), 1/8/2013
|
||||
:toc:
|
||||
:toc-placement: preamble
|
||||
:sectanchors:
|
||||
|
||||
This document defines a network protocol for a key-value store that may be read
|
||||
from and written to by multiple remote clients. A central server, most often
|
||||
running on a FIRST FRC robot controller, is responsible for providing
|
||||
information consistency and for facilitating communication between clients.
|
||||
|
||||
Information consistency is guaranteed through the use of a sequence number
|
||||
associated with each key-value pair. An update of a key-value pair increments
|
||||
the associated sequence number, and this update information is shared with all
|
||||
participating clients. The central server only applies and redistributes
|
||||
updates which have a larger sequence number than its own, which guarantees that
|
||||
a client must have received a server's most recent state before it can replace
|
||||
it with a new value.
|
||||
|
||||
This is a backwards-incompatible rework of the Network Tables network protocol
|
||||
originally introduced for the 2012 FIRST Robotics Competition. Note that this
|
||||
revision of the Network Tables protocol no longer includes the concept of
|
||||
sub-tables. We suggest that instead of representing sub-tables as first-class
|
||||
data types in the network protocol, it would be easy for an implementation to
|
||||
provide a similar API abstraction by adding prefixes to keys. For example, we
|
||||
suggest using Unix-style path strings to define sub-table hierarchies. The
|
||||
prefix ensures that sub-table namespaces do not collide in a global hashtable
|
||||
without requiring an explicit sub-table representation.
|
||||
|
||||
In addition, the explicit concept of grouping multiple updates such that they
|
||||
are all visible at the same time to user code on a remote device was discarded.
|
||||
Instead, array types for all common elements are provided. By using an array
|
||||
data type, users may achieve the same level of atomicity for common operations
|
||||
(e.g. sending a cartesian coordinate pair) without requiring the complexity of
|
||||
arbitrarily grouped updates.
|
||||
|
||||
This document conforms to <<rfc2119>> - Key words for use in RFCs to Indicate
|
||||
Requirement Levels.
|
||||
|
||||
[[references]]
|
||||
== References
|
||||
|
||||
[[rfc1982,RFC 1982]]
|
||||
* RFC 1982, Serial Number Arithmetic, http://tools.ietf.org/html/rfc1982
|
||||
|
||||
[[rfc2119,RFC 2119]]
|
||||
* RFC 2119, Key words for use in RFCs to Indicate Requirement Levels,
|
||||
http://tools.ietf.org/html/rfc2119
|
||||
|
||||
[[definitions]]
|
||||
== Definitions
|
||||
|
||||
[[def-client]]
|
||||
Client:: An implementation of this protocol running in client configuration.
|
||||
Any number of Clients may exist for a given Network.
|
||||
|
||||
[[def-entry]]
|
||||
Entry:: A data value identified by a string name.
|
||||
|
||||
[[def-entry-id]]
|
||||
Entry ID:: An unsigned 2-byte ID by which the Server and Clients refer to an
|
||||
Entry across the network instead of using the full string key for the Entry.
|
||||
Entry IDs range from 0x0000 to 0xFFFE (0xFFFF is reserved for an Entry
|
||||
Assignment issued by a Client).
|
||||
|
||||
[[def-server]]
|
||||
Server:: An implementation of this protocol running in server configuration.
|
||||
One and only one Server must exist for a given Network.
|
||||
|
||||
[[def-network]]
|
||||
Network:: One or more Client nodes connected to a Server.
|
||||
|
||||
[[def-user-code]]
|
||||
User Code:: User-supplied code which may interact with a Client or Server. User
|
||||
Code should be executed on the same computer as the Client or Server instance
|
||||
it interacts with.
|
||||
|
||||
[[def-sequence-number]]
|
||||
Sequence Number:: An unsigned number which allows the Server to resolve update
|
||||
conflicts between Clients and/or the Server. Sequence numbers may overflow.
|
||||
Sequential arithmetic comparisons, which must be used with Sequence Numbers,
|
||||
are defined by RFC 1982.
|
||||
|
||||
[[def-protocol-revision]]
|
||||
Protocol Revision:: A 16-bit unsigned integer which indicates the version of
|
||||
the network tables protocol that a client wishes to use. The protocol revision
|
||||
assigned to this version of the network tables specification is listed at the
|
||||
top of this document. This number is listed in dot-decimal notation as well as
|
||||
its equivalent hexadecimal value.
|
||||
|
||||
== Transport Layer
|
||||
|
||||
Conventional implementations of this protocol should use TCP for reliable
|
||||
communication; the Server should listen on TCP port 1735 for incoming
|
||||
connections.
|
||||
|
||||
== Example Exchanges
|
||||
|
||||
[[exchange-connect]]
|
||||
=== Client Connects to the Server
|
||||
|
||||
Directly after client establishes a connection with the Server, the following
|
||||
procedure must be followed:
|
||||
|
||||
. The Client sends a <<msg-client-hello>> message to the Server
|
||||
|
||||
. The Server sends one <<msg-assign>> for every field it currently recognizes.
|
||||
|
||||
. The Server sends a <<msg-server-hello-complete>> message.
|
||||
|
||||
. For all Entries the Client recognizes that the Server did not identify with a
|
||||
Entry Assignment, the client follows the <<exchange-client-creates-entry>>
|
||||
protocol.
|
||||
|
||||
In the event that the Server does not support the protocol revision that the
|
||||
Client has requested in a Client Hello message, the Server must instead issue a
|
||||
<<msg-protocol-unsupported>> message to the joining client and close the
|
||||
connection.
|
||||
|
||||
[[exchange-client-creates-entry]]
|
||||
=== Client Creates an Entry
|
||||
|
||||
When User Code on a Client assigns a value to an Entry that the Server has not
|
||||
yet issued a Entry Assignment for, the following procedure must be followed:
|
||||
|
||||
. The Client sends an <<msg-assign>> with an Entry ID of 0xFFFF.
|
||||
|
||||
. The Server issues an <<msg-assign>> to all Clients (including the sender) for
|
||||
the new field containing a real Entry ID and Sequence Number for the new field.
|
||||
|
||||
In the event that User Code on the Client updates the value of the
|
||||
to-be-announced field again before the expected Entry Assignment is received,
|
||||
then the Client must save the new value and take no other action (the most
|
||||
recent value of the field should be issued when the Entry Assignment arrives,
|
||||
if it differs from the value contained in the received Entry Assignment).
|
||||
|
||||
In the event that the Client receives a Entry Assignment from the Server for
|
||||
the Entry that it intended to issue an Entry Assignment for, before it issued
|
||||
its own Entry Assignment, the procedure may end early.
|
||||
|
||||
In the event that the Server receives a duplicate Entry Assignment from a
|
||||
Client (likely due to the client having not yet received the Server's Entry
|
||||
Assignment), the Server should ignore the duplicate Entry Assignment.
|
||||
|
||||
[[exchange-client-updates-entry]]
|
||||
=== Client Updates an Entry
|
||||
|
||||
When User Code on a Client updates the value of an Entry, the Client must send
|
||||
an <<msg-update>> message to the Server. The Sequence Number included in the
|
||||
Entry Update message must be the most recently received Sequence Number for the
|
||||
Entry to be updated incremented by one.
|
||||
|
||||
.Example:
|
||||
|
||||
. Client receives Entry Assignment message for Entry "a" with integer value 1,
|
||||
Entry ID of 0, and Sequence Number 1.
|
||||
|
||||
. User Code on Client updates value of Entry "a" to 16 (arbitrary).
|
||||
|
||||
. Client sends Entry Update message to Server for Entry 0 with a Sequence
|
||||
Number of 2 and a value of 16.
|
||||
|
||||
When the Server receives an Entry Update message, it first checks the Sequence
|
||||
Number in the message against the Server's value for the Sequence Number
|
||||
associated with the Entry to be updated. If the received Sequence Number is
|
||||
strictly greater than (aside: see definition of "greater than" under the
|
||||
definition of Sequence Number) the Server's Sequence Number for the Entry to be
|
||||
updated, the Server must apply the new value for the indicated Entry and repeat
|
||||
the Entry Update message to all other connected Clients.
|
||||
|
||||
If the received Sequence Number is less than or equal (see definition of "less
|
||||
than or equal" in RFC 1982) to the Server's Sequence Number for the Entry to be
|
||||
updated, this implies that the Client which issued the Entry Update message has
|
||||
not yet received one or more Entry Update message(s) that the Server recently
|
||||
sent to it; therefore, the Server must ignore the received Entry Update
|
||||
message. In the event that comparison between two Sequence Numbers is undefined
|
||||
(see RFC 1982), then the Server must always win (it ignores the Entry Update
|
||||
message under consideration).
|
||||
|
||||
[[update-rate]]
|
||||
NOTE: If User Code modifies the value of an Entry too quickly, 1) users may not
|
||||
see every value appear on remote machines, and 2) the consistency protection
|
||||
offered by the Entry's Sequence Number may be lost (by overflowing before
|
||||
remote devices hear recent values). It is recommended that implementations
|
||||
detect when user code updates an Entry more frequently than once every 5
|
||||
milliseconds and print a warning message to the user (and/or offer some other
|
||||
means of informing User Code of this condition).
|
||||
|
||||
[[exchange-server-creates-entry]]
|
||||
=== Server Creates an Entry
|
||||
|
||||
When User Code on the Server assigns a value to a Entry which does not exist,
|
||||
the Server must issue an <<msg-assign>> message to all connected clients.
|
||||
|
||||
[[exchange-server-updates-entry]]
|
||||
=== Server Updates an Entry
|
||||
|
||||
When User Code on the Server updates the value of an Entry, the Server must
|
||||
apply the new value to the Entry immediately, increment the associated Entry's
|
||||
Sequence Number, and issue a <<msg-update>> message containing the new value
|
||||
and Sequence Number of the associated Entry to all connected Clients.
|
||||
|
||||
NOTE: See <<update-rate,Note>> under <<exchange-client-updates-entry>>.
|
||||
|
||||
[[exchange-keep-alive]]
|
||||
=== Keep Alive
|
||||
|
||||
To maintain a connection and prove a socket is still open, a Client or Server
|
||||
may issue <<msg-keep-alive>> messages. Clients and the Server should ignore
|
||||
incoming Keep Alive messages.
|
||||
|
||||
The intent is that by writing a Keep Alive to a socket, a Client forces its
|
||||
network layer (TCP) to reevaluate the state of the network connection as it
|
||||
attempts to deliver the Keep Alive message. In the event that a connection is
|
||||
no longer usable, a Client's network layer should inform the Client that it is
|
||||
no longer usable within a few attempts to send a Keep Alive message.
|
||||
|
||||
To provide timely connection status information, Clients should send a Keep
|
||||
Alive message to the Server after every 1 second period of connection
|
||||
inactivity (i.e. no information is being sent to the Server). Clients should
|
||||
not send Keep Alive messages more frequently than once every 100 milliseconds.
|
||||
|
||||
Since the Server does not require as timely information about the status of a
|
||||
connection, it is not required to send Keep Alive messages during a period of
|
||||
inactivity.
|
||||
|
||||
[[bandwidth]]
|
||||
== Bandwidth and Latency Considerations
|
||||
|
||||
To reduce unnecessary bandwidth usage, implementations of this protocol should:
|
||||
|
||||
* Send an Entry Update if and only if the value of an Entry is changed to a
|
||||
value that is different from its prior value.
|
||||
|
||||
* Buffer messages and transmit them in groups, when possible, to reduce
|
||||
transport protocol overhead.
|
||||
|
||||
* Only send the most recent value of an Entry. When User Code updates the value
|
||||
of an Entry more than once before the new value is transmitted, only the latest
|
||||
value of the Entry should be sent.
|
||||
|
||||
It is important to note that these behaviors will increase the latency between
|
||||
when a Client or Server updates the value of an Entry and when all Clients
|
||||
reflect the new value. The exact behavior of this buffering is left to
|
||||
implementations to determine, although the chosen scheme should reflect the
|
||||
needs of User Code. Implementations may include a method by which User Code can
|
||||
specify the maximum tolerable send latency.
|
||||
|
||||
[[entry-types]]
|
||||
== Entry Types
|
||||
|
||||
Entry Type must assume one the following values:
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Numeric Value |Type
|
||||
|
||||
|0x00
|
||||
|Boolean
|
||||
|
||||
|0x01
|
||||
|Double
|
||||
|
||||
|0x02
|
||||
|String
|
||||
|
||||
|0x10
|
||||
|Boolean Array
|
||||
|
||||
|0x11
|
||||
|Double Array
|
||||
|
||||
|0x12
|
||||
|String Array
|
||||
|===
|
||||
|
||||
[[entry-values]]
|
||||
== Entry Values
|
||||
|
||||
Entry Value must assume the following structure as indicated by Entry Type:
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Entry Type |Entry Value Format
|
||||
|
||||
|[[entry-value-boolean]]Boolean
|
||||
|1 byte, unsigned; True = 0x01, False = 0x00
|
||||
|
||||
|[[entry-value-double]]Double
|
||||
|8 bytes, IEEE 754 floating-point "double format" bit layout; (big endian)
|
||||
|
||||
|[[entry-value-string]]String
|
||||
|2 byte, unsigned length prefix (big endian) of the number of raw bytes to
|
||||
follow, followed by the string encoded in UTF-8
|
||||
|
||||
|[[entry-value-boolean-array]]Boolean Array
|
||||
|1 byte, unsigned, number of elements within the array to follow
|
||||
|
||||
N bytes - The raw bytes representing each Boolean element contained within the
|
||||
array, beginning with the item at index 0 within the array.
|
||||
|
||||
|[[entry-value-double-array]]Double Array
|
||||
|1 byte, unsigned, number of elements within the array to follow
|
||||
|
||||
N bytes - The raw bytes representing each Double element contained within the
|
||||
array, beginning with the item at index 0 within the array.
|
||||
|
||||
|[[entry-value-string-array]]String Array
|
||||
|1 byte, unsigned, number of elements within the array to follow
|
||||
|
||||
N bytes - The raw bytes representing each String element contained within the
|
||||
array, beginning with the item at index 0 within the array.
|
||||
|===
|
||||
|
||||
== Message Structures
|
||||
|
||||
All messages are of the following format:
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|Message Type
|
||||
|1 byte, unsigned
|
||||
|
||||
|Message Data
|
||||
|N bytes (length determined by Message Type)
|
||||
|===
|
||||
|
||||
[[msg-keep-alive]]
|
||||
=== Keep Alive
|
||||
|
||||
Indicates that the remote party is checking the status of a network connection.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x00 - Keep Alive
|
||||
|1 byte, unsigned; Message Type
|
||||
|===
|
||||
|
||||
[[msg-client-hello]]
|
||||
=== Client Hello
|
||||
|
||||
A Client issues a Client Hello message when first establishing a connection.
|
||||
The Client Protocol Revision field specifies the Network Table protocol
|
||||
revision that the Client would like to use.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x01 - Client Hello
|
||||
|1 byte, unsigned; Message Type
|
||||
|
||||
|Client Protocol Revision
|
||||
|2 bytes, Unsigned 16-bit integer (big-endian).
|
||||
|
||||
See <<def-protocol-revision,Protocol Revision>>
|
||||
|===
|
||||
|
||||
[[msg-protocol-unsupported]]
|
||||
=== Protocol Version Unsupported
|
||||
|
||||
A Server issues a Protocol Version Unsupported message to a Client to inform it
|
||||
that the requested protocol revision is not supported. It also includes the
|
||||
most recent protocol revision which it supports, such that a Client may
|
||||
reconnect under a prior protocol revision if able.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x02 - Protocol Version Unsupported
|
||||
|1 byte, unsigned; Message Type
|
||||
|
||||
|Server Supported Protocol Revision
|
||||
|2 bytes, Unsigned 16-bit integer (big-endian).
|
||||
|
||||
See <<def-protocol-revision,Protocol Revision>>
|
||||
|===
|
||||
|
||||
[[msg-server-hello-complete]]
|
||||
=== Server Hello Complete
|
||||
|
||||
A Server issues a Server Hello Complete message when it has finished informing
|
||||
a newly-connected client of all of the fields it currently recognizes.
|
||||
Following the receipt of this message, a Client should inform the Server of
|
||||
any/all additional fields that it recognizes that the Server did not announce.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x03 - Server Hello Complete
|
||||
|1 byte, unsigned; Message Type
|
||||
|===
|
||||
|
||||
[[msg-assign]]
|
||||
=== Entry Assignment
|
||||
|
||||
A Entry Assignment message informs the remote party of a new Entry. An Entry
|
||||
Assignment's value field must be the most recent value of the field being
|
||||
assigned at the time that the Entry Assignment is sent.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x10 - Entry Assignment
|
||||
|1 byte, unsigned; Message Type
|
||||
|
||||
|Entry Name
|
||||
|<<entry-value-string,String>>
|
||||
|
||||
|Entry Type
|
||||
|1 byte, unsigned; see <<entry-types,Entry Types>>
|
||||
|
||||
|Entry ID
|
||||
|2 bytes, unsigned
|
||||
|
||||
|Entry Sequence Number
|
||||
|2 bytes, unsigned
|
||||
|
||||
|Entry Value
|
||||
|N bytes, length depends on Entry Type
|
||||
|===
|
||||
|
||||
If the Entry ID is 0xFFFF, then this assignment represents a request from a
|
||||
Client to the Server. In this event, the Entry ID field and the Entry Sequence
|
||||
Number field must not be stored or relied upon as they otherwise would be.
|
||||
|
||||
[[msg-update]]
|
||||
=== Entry Update
|
||||
|
||||
An Entry Update message informs a remote party of a new value for an Entry.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x11 - Entry Update
|
||||
|1 byte, unsigned; Message Type
|
||||
|
||||
|Entry ID
|
||||
|2 bytes, unsigned
|
||||
|
||||
|Entry Sequence Number
|
||||
|2 bytes, unsigned
|
||||
|
||||
|Entry Value
|
||||
|N bytes, length dependent on value type
|
||||
|===
|
||||
838
doc/networktables3.adoc
Normal file
838
doc/networktables3.adoc
Normal file
@@ -0,0 +1,838 @@
|
||||
= Network Tables Protocol Specification, Version 3.0
|
||||
Protocol Revision 3.0 (0x0300), 6/12/2015
|
||||
:toc:
|
||||
:toc-placement: preamble
|
||||
:sectanchors:
|
||||
|
||||
This document defines a network protocol for a key-value store that may be read
|
||||
from and written to by multiple remote clients. A central server, most often
|
||||
running on a FIRST FRC robot controller, is responsible for providing
|
||||
information consistency and for facilitating communication between clients.
|
||||
|
||||
Information consistency is guaranteed through the use of a sequence number
|
||||
associated with each key-value pair. An update of a key-value pair increments
|
||||
the associated sequence number, and this update information is shared with all
|
||||
participating clients. The central server only applies and redistributes
|
||||
updates which have a larger sequence number than its own, which guarantees that
|
||||
a client must have received a server's most recent state before it can replace
|
||||
it with a new value.
|
||||
|
||||
This is a backwards-compatible update of <<networktables2,version 2.0>> of the
|
||||
Network Tables network protocol. The protocol is designed such that 3.0 clients
|
||||
and servers can interoperate with 2.0 clients and servers with the only loss of
|
||||
functionality being the extended features introduced in 3.0.
|
||||
|
||||
This document conforms to <<rfc2119>> - Key words for use in RFCs to Indicate
|
||||
Requirement Levels.
|
||||
|
||||
== Summary of Changes from 2.0 to 3.0
|
||||
|
||||
3 way connection handshake:: When a Client establishes a connection, after
|
||||
receiving the <<msg-server-hello-complete>> message and sending its local
|
||||
entries, it finishes with a <<msg-client-hello-complete>> message to the
|
||||
server. This enables the Server to be aware of when the Client is fully
|
||||
synchronized.
|
||||
|
||||
String length encoding:: String length is now encoded as unsigned <<leb128>>
|
||||
rather than as a 2-byte unsigned integer. This both allows string lengths
|
||||
longer than 64K and is more space efficient for the common case of short
|
||||
strings (<128 byte strings only require a single byte for length).
|
||||
|
||||
Entry deletion:: Entries may now be deleted by any member of the Network using
|
||||
the <<msg-delete>> and <<msg-clear-all>> messages. Note that in a Network
|
||||
consisting of mixed 2.0 and 3.0 Clients, deletion may be ineffective because
|
||||
the deletion message will not be propagated to the 2.0 Clients.
|
||||
|
||||
// TODO: needs more description in the text of how these messages are
|
||||
// propagated
|
||||
|
||||
Remote procedure call:: The Server may create specially-typed entries that
|
||||
inform Clients of remotely callable functions on the Server. Clients can then
|
||||
execute these functions via the Network Tables protocol. See <<rpc-operation>>.
|
||||
|
||||
Raw data type:: An arbitrary data type has been added. While string could be
|
||||
used to encode raw data, the reason for a different data type is so that
|
||||
dashboards can choose not to display the raw data (or display it in a different
|
||||
format).
|
||||
|
||||
Client and server self-identification:: Clients self-identify with a
|
||||
user-defined string name when connecting to the Server (this is part of the new
|
||||
<<msg-client-hello-complete>> message). This provides a more reliable method
|
||||
than simply the remote IP address for determining on the Server side whether or
|
||||
not a particular Client is connected. While Clients are less likely to care
|
||||
what Server they are connected to, for completeness a similar Server
|
||||
self-identification string has been added to the Server Hello Complete message.
|
||||
Note that Server connection information is not provided from the Server to
|
||||
Clients (at least in a way built into the protocol), so it is not possible for
|
||||
a Client to determine what other Clients are connected to the Server.
|
||||
|
||||
Server reboot detection:: The Server keeps an internal list of all Client
|
||||
identity strings that have ever connected to it (this list is always empty at
|
||||
Server start). During the initial connection process, the Server sends the
|
||||
Client a flag (as part of the new <<msg-server-hello>> message) that indicates
|
||||
whether or not the Client was already on this list. Clients use this flag to
|
||||
determine whether the Server has rebooted since the previous connection.
|
||||
|
||||
Entry flags:: Each Entry now has an 8-bit flags value associated with it (see
|
||||
<<entry-flags>>). The initial value of the flags are provided as part of the
|
||||
<<msg-assign>> message. The value of the flags may be updated by any member of
|
||||
the Network via use of the <<msg-flags-update>> message.
|
||||
|
||||
Entry persistence:: The Server is required to provide a feature to
|
||||
automatically save entries (including their last known values) across Server
|
||||
restarts. By default, no values are automatically saved in this manner, but
|
||||
any member of the Network may set the “Persistent” Entry Flag on an Entry to
|
||||
indicate to the server that the Entry must be persisted by the Server. The
|
||||
Server must periodically save such flagged Entries to a file; on Server start,
|
||||
the Server reads the file to create the initial set of Server Entries.
|
||||
|
||||
More robust Entry Update message encoding:: The entry type has been added to
|
||||
the <<msg-update>> message. This is used only to specify the length of value
|
||||
encoded in the Entry Update message, and has no effect on the Client or Server
|
||||
handling of Entry Updates. Clients and Servers must ignore Entry Update
|
||||
messages with mismatching type to their currently stored value. This increases
|
||||
robustness of Entry Updates in the presence of Entry Assignments with varying
|
||||
type (which should be uncommon, but this fixes a weakness in the 2.0 protocol).
|
||||
|
||||
////
|
||||
TODO
|
||||
|
||||
Synchronization on reconnect:: The approach to how Clients should handle
|
||||
conflicting values when reconnecting to a Server has been clarified.
|
||||
|
||||
////
|
||||
|
||||
[[references]]
|
||||
== References
|
||||
|
||||
[[networktables2]]
|
||||
* <<networktables2.adoc#,Network Tables Protocol Specification, Protocol
|
||||
Revision 2.0 (0x0200)>>, dated 1/8/2013.
|
||||
|
||||
[[leb128,LEB128]]
|
||||
* LEB128 definition in DWARF Specification 3.0
|
||||
(http://dwarfstd.org/doc/Dwarf3.pdf, section 7.6 and Appendix C, also explained
|
||||
in http://en.wikipedia.org/wiki/LEB128)
|
||||
|
||||
[[rfc1982,RFC1982]]
|
||||
* RFC 1982, Serial Number Arithmetic, http://tools.ietf.org/html/rfc1982
|
||||
|
||||
[[rfc2119,RFC2119]]
|
||||
* RFC 2119, Key words for use in RFCs to Indicate Requirement Levels,
|
||||
http://tools.ietf.org/html/rfc2119
|
||||
|
||||
[[definitions]]
|
||||
== Definitions
|
||||
|
||||
[[def-client]]
|
||||
Client:: An implementation of this protocol running in client configuration.
|
||||
Any number of Clients may exist for a given Network.
|
||||
|
||||
[[def-entry]]
|
||||
Entry:: A data value identified by a string name.
|
||||
|
||||
[[def-entry-id]]
|
||||
Entry ID:: An unsigned 2-byte ID by which the Server and Clients refer to an
|
||||
Entry across the network instead of using the full string key for the Entry.
|
||||
Entry IDs range from 0x0000 to 0xFFFE (0xFFFF is reserved for an Entry
|
||||
Assignment issued by a Client).
|
||||
|
||||
[[def-server]]
|
||||
Server:: An implementation of this protocol running in server configuration.
|
||||
One and only one Server must exist for a given Network.
|
||||
|
||||
[[def-network]]
|
||||
Network:: One or more Client nodes connected to a Server.
|
||||
|
||||
[[def-user-code]]
|
||||
User Code:: User-supplied code which may interact with a Client or Server. User
|
||||
Code should be executed on the same computer as the Client or Server instance
|
||||
it interacts with.
|
||||
|
||||
[[def-sequence-number]]
|
||||
Sequence Number:: An unsigned number which allows the Server to resolve update
|
||||
conflicts between Clients and/or the Server. Sequence numbers may overflow.
|
||||
Sequential arithmetic comparisons, which must be used with Sequence Numbers,
|
||||
are defined by <<rfc1982>>.
|
||||
|
||||
[[def-protocol-revision]]
|
||||
Protocol Revision:: A 16-bit unsigned integer which indicates the version of
|
||||
the network tables protocol that a client wishes to use. The protocol revision
|
||||
assigned to this version of the network tables specification is listed at the
|
||||
top of this document. This number is listed in dot-decimal notation as well as
|
||||
its equivalent hexadecimal value.
|
||||
|
||||
== Transport Layer
|
||||
|
||||
Conventional implementations of this protocol should use TCP for reliable
|
||||
communication; the Server should listen on TCP port 1735 for incoming
|
||||
connections.
|
||||
|
||||
== Example Exchanges
|
||||
|
||||
[[exchange-connect]]
|
||||
=== Client Connects to the Server
|
||||
|
||||
Directly after client establishes a connection with the Server, the following
|
||||
procedure must be followed:
|
||||
|
||||
. The Client sends a <<msg-client-hello>> message to the Server
|
||||
|
||||
. The Server sends a <<msg-server-hello>> message.
|
||||
|
||||
. The Server sends one <<msg-assign>> for every field it currently recognizes.
|
||||
|
||||
. The Server sends a <<msg-server-hello-complete>> message.
|
||||
|
||||
. For all Entries the Client recognizes that the Server did not identify with a
|
||||
Entry Assignment, the client follows the <<exchange-client-creates-entry>>
|
||||
protocol.
|
||||
|
||||
. The Client sends a <<msg-client-hello-complete>> message.
|
||||
|
||||
In the event that the Server does not support the protocol revision that the
|
||||
Client has requested in a Client Hello message, the Server must instead issue a
|
||||
<<msg-protocol-unsupported>> message to the joining client and close the
|
||||
connection.
|
||||
|
||||
[[exchange-client-creates-entry]]
|
||||
=== Client Creates an Entry
|
||||
|
||||
When User Code on a Client assigns a value to an Entry that the Server has not
|
||||
yet issued a Entry Assignment for, the following procedure must be followed:
|
||||
|
||||
. The Client sends an <<msg-assign>> with an Entry ID of 0xFFFF.
|
||||
|
||||
. The Server issues an <<msg-assign>> to all Clients (including the sender) for
|
||||
the new field containing a real Entry ID and Sequence Number for the new field.
|
||||
|
||||
In the event that User Code on the Client updates the value of the
|
||||
to-be-announced field again before the expected Entry Assignment is received,
|
||||
then the Client must save the new value and take no other action (the most
|
||||
recent value of the field should be issued when the Entry Assignment arrives,
|
||||
if it differs from the value contained in the received Entry Assignment).
|
||||
|
||||
In the event that the Client receives a Entry Assignment from the Server for
|
||||
the Entry that it intended to issue an Entry Assignment for, before it issued
|
||||
its own Entry Assignment, the procedure may end early.
|
||||
|
||||
In the event that the Server receives a duplicate Entry Assignment from a
|
||||
Client (likely due to the client having not yet received the Server's Entry
|
||||
Assignment), the Server should ignore the duplicate Entry Assignment.
|
||||
|
||||
[[exchange-client-updates-entry]]
|
||||
=== Client Updates an Entry
|
||||
|
||||
When User Code on a Client updates the value of an Entry, the Client must send
|
||||
an <<msg-update>> message to the Server. The Sequence Number included in the
|
||||
Entry Update message must be the most recently received Sequence Number for the
|
||||
Entry to be updated incremented by one.
|
||||
|
||||
.Example:
|
||||
|
||||
. Client receives Entry Assignment message for Entry "a" with integer value 1,
|
||||
Entry ID of 0, and Sequence Number 1.
|
||||
|
||||
. User Code on Client updates value of Entry "a" to 16 (arbitrary).
|
||||
|
||||
. Client sends Entry Update message to Server for Entry 0 with a Sequence
|
||||
Number of 2 and a value of 16.
|
||||
|
||||
When the Server receives an Entry Update message, it first checks the Sequence
|
||||
Number in the message against the Server's value for the Sequence Number
|
||||
associated with the Entry to be updated. If the received Sequence Number is
|
||||
strictly greater than (aside: see definition of "greater than" under the
|
||||
definition of Sequence Number) the Server's Sequence Number for the Entry to be
|
||||
updated, the Server must apply the new value for the indicated Entry and repeat
|
||||
the Entry Update message to all other connected Clients.
|
||||
|
||||
If the received Sequence Number is less than or equal (see definition of "less
|
||||
than or equal" in RFC 1982) to the Server's Sequence Number for the Entry to be
|
||||
updated, this implies that the Client which issued the Entry Update message has
|
||||
not yet received one or more Entry Update message(s) that the Server recently
|
||||
sent to it; therefore, the Server must ignore the received Entry Update
|
||||
message. In the event that comparison between two Sequence Numbers is undefined
|
||||
(see RFC 1982), then the Server must always win (it ignores the Entry Update
|
||||
message under consideration).
|
||||
|
||||
[[update-rate]]
|
||||
NOTE: If User Code modifies the value of an Entry too quickly, 1) users may not
|
||||
see every value appear on remote machines, and 2) the consistency protection
|
||||
offered by the Entry's Sequence Number may be lost (by overflowing before
|
||||
remote devices hear recent values). It is recommended that implementations
|
||||
detect when user code updates an Entry more frequently than once every 5
|
||||
milliseconds and print a warning message to the user (and/or offer some other
|
||||
means of informing User Code of this condition).
|
||||
|
||||
[[exchange-client-updates-flags]]
|
||||
=== Client Updates an Entry's Flags
|
||||
|
||||
When User Code on a Client updates an Entry's flags, the Client must apply the
|
||||
new flags to the Entry immediately, and send an <<msg-flags-update>> message to
|
||||
the Server.
|
||||
|
||||
When the Server receives an Entry Flags Update message, it must apply the new
|
||||
flags to the indicated Entry and repeat the Entry Flags Update message to all
|
||||
other connected Clients.
|
||||
|
||||
[[exchange-client-deletes-entry]]
|
||||
=== Client Deletes an Entry
|
||||
|
||||
When User Code on a Client deletes an Entry, the Client must immediately delete
|
||||
the Entry, and send an <<msg-delete>> message to the Server.
|
||||
|
||||
When the Server receives an Entry Delete message, it must delete the indicated
|
||||
Entry and repeat the Entry Delete message to all other connected Clients.
|
||||
|
||||
[[exchange-server-creates-entry]]
|
||||
=== Server Creates an Entry
|
||||
|
||||
When User Code on the Server assigns a value to a Entry which does not exist,
|
||||
the Server must issue an <<msg-assign>> message to all connected clients.
|
||||
|
||||
[[exchange-server-updates-entry]]
|
||||
=== Server Updates an Entry
|
||||
|
||||
When User Code on the Server updates the value of an Entry, the Server must
|
||||
apply the new value to the Entry immediately, increment the associated Entry's
|
||||
Sequence Number, and issue a <<msg-update>> message containing the new value
|
||||
and Sequence Number of the associated Entry to all connected Clients.
|
||||
|
||||
NOTE: See <<update-rate,Note>> under <<exchange-client-updates-entry>>.
|
||||
|
||||
[[exchange-server-updates-flags]]
|
||||
=== Server Updates an Entry's Flags
|
||||
|
||||
When User Code on the Server updates an Entry's flags, the Server must apply
|
||||
the new flags to the Entry immediately, and issue a <<msg-flags-update>>
|
||||
message containing the new flags value to all connected Clients.
|
||||
|
||||
[[exchange-server-deletes-entry]]
|
||||
=== Server Deletes an Entry
|
||||
|
||||
When User Code on the Server deletes an Entry, the Server must immediately
|
||||
delete the Entry, and issue a <<msg-delete>> message to all connected Clients.
|
||||
|
||||
[[exchange-keep-alive]]
|
||||
=== Keep Alive
|
||||
|
||||
To maintain a connection and prove a socket is still open, a Client or Server
|
||||
may issue <<msg-keep-alive>> messages. Clients and the Server should ignore
|
||||
incoming Keep Alive messages.
|
||||
|
||||
The intent is that by writing a Keep Alive to a socket, a Client forces its
|
||||
network layer (TCP) to reevaluate the state of the network connection as it
|
||||
attempts to deliver the Keep Alive message. In the event that a connection is
|
||||
no longer usable, a Client's network layer should inform the Client that it is
|
||||
no longer usable within a few attempts to send a Keep Alive message.
|
||||
|
||||
To provide timely connection status information, Clients should send a Keep
|
||||
Alive message to the Server after every 1 second period of connection
|
||||
inactivity (i.e. no information is being sent to the Server). Clients should
|
||||
not send Keep Alive messages more frequently than once every 100 milliseconds.
|
||||
|
||||
Since the Server does not require as timely information about the status of a
|
||||
connection, it is not required to send Keep Alive messages during a period of
|
||||
inactivity.
|
||||
|
||||
[[bandwidth]]
|
||||
== Bandwidth and Latency Considerations
|
||||
|
||||
To reduce unnecessary bandwidth usage, implementations of this protocol should:
|
||||
|
||||
* Send an Entry Update if and only if the value of an Entry is changed to a
|
||||
value that is different from its prior value.
|
||||
|
||||
* Buffer messages and transmit them in groups, when possible, to reduce
|
||||
transport protocol overhead.
|
||||
|
||||
* Only send the most recent value of an Entry. When User Code updates the value
|
||||
of an Entry more than once before the new value is transmitted, only the latest
|
||||
value of the Entry should be sent.
|
||||
|
||||
It is important to note that these behaviors will increase the latency between
|
||||
when a Client or Server updates the value of an Entry and when all Clients
|
||||
reflect the new value. The exact behavior of this buffering is left to
|
||||
implementations to determine, although the chosen scheme should reflect the
|
||||
needs of User Code. Implementations may include a method by which User Code can
|
||||
specify the maximum tolerable send latency.
|
||||
|
||||
[[entry-types]]
|
||||
== Entry Types
|
||||
|
||||
Entry Type must assume one the following values:
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Numeric Value |Type
|
||||
|
||||
|0x00
|
||||
|Boolean
|
||||
|
||||
|0x01
|
||||
|Double
|
||||
|
||||
|0x02
|
||||
|String
|
||||
|
||||
|0x03
|
||||
|Raw Data
|
||||
|
||||
|0x10
|
||||
|Boolean Array
|
||||
|
||||
|0x11
|
||||
|Double Array
|
||||
|
||||
|0x12
|
||||
|String Array
|
||||
|
||||
|0x20
|
||||
|Remote Procedure Call Definition
|
||||
|===
|
||||
|
||||
[[entry-values]]
|
||||
== Entry Values
|
||||
|
||||
Entry Value must assume the following structure as indicated by Entry Type:
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Entry Type |Entry Value Format
|
||||
|
||||
|[[entry-value-boolean]]Boolean
|
||||
|1 byte, unsigned; True = 0x01, False = 0x00
|
||||
|
||||
|[[entry-value-double]]Double
|
||||
|8 bytes, IEEE 754 floating-point "double format" bit layout; (big endian)
|
||||
|
||||
|[[entry-value-string]]String
|
||||
|N bytes, unsigned <<leb128>> encoded length of the number of raw bytes to
|
||||
follow, followed by the string encoded in UTF-8
|
||||
|
||||
|[[entry-value-raw]]Raw Data
|
||||
|N bytes, unsigned LEB128 encoded length of the number of raw bytes to follow,
|
||||
followed by the raw bytes.
|
||||
|
||||
While the raw data definition is unspecified, it's recommended that users use
|
||||
the first byte of the raw data to "tag" the type of data actually being stored.
|
||||
|
||||
|[[entry-value-boolean-array]]Boolean Array
|
||||
|1 byte, unsigned, number of elements within the array to follow
|
||||
|
||||
N bytes - The raw bytes representing each Boolean element contained within the
|
||||
array, beginning with the item at index 0 within the array.
|
||||
|
||||
|[[entry-value-double-array]]Double Array
|
||||
|1 byte, unsigned, number of elements within the array to follow
|
||||
|
||||
N bytes - The raw bytes representing each Double element contained within the
|
||||
array, beginning with the item at index 0 within the array.
|
||||
|
||||
|[[entry-value-string-array]]String Array
|
||||
|1 byte, unsigned, number of elements within the array to follow
|
||||
|
||||
N bytes - The raw bytes representing each String element contained within the
|
||||
array, beginning with the item at index 0 within the array.
|
||||
|
||||
|[[entry-value-rpc]]Remote Procedure Call Definition
|
||||
|N bytes, unsigned LEB128 encoded length of the number of raw bytes to follow.
|
||||
|
||||
N bytes - data as defined in Remote Procedure Call Definition Data
|
||||
|===
|
||||
|
||||
[[entry-flags]]
|
||||
== Entry Flags
|
||||
|
||||
Entry Flags are as follows:
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Bit Mask |Bit Value Meaning
|
||||
|
||||
|[[entry-flag-persistent]]0x01 (least significant bit) - Persistent
|
||||
|
||||
|0x00: Entry is not persistent. The entry and its value will not be retained
|
||||
across a server restart.
|
||||
|
||||
0x01: Entry is persistent. Updates to the value are automatically saved and
|
||||
the entry will be automatically created and the last known value restored when
|
||||
the server starts.
|
||||
|
||||
|0xFE
|
||||
|Reserved
|
||||
|===
|
||||
|
||||
== Message Structures
|
||||
|
||||
All messages are of the following format:
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|Message Type
|
||||
|1 byte, unsigned
|
||||
|
||||
|Message Data
|
||||
|N bytes (length determined by Message Type)
|
||||
|===
|
||||
|
||||
[[msg-keep-alive]]
|
||||
=== Keep Alive
|
||||
|
||||
Indicates that the remote party is checking the status of a network connection.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x00 - Keep Alive
|
||||
|1 byte, unsigned; Message Type
|
||||
|===
|
||||
|
||||
[[msg-client-hello]]
|
||||
=== Client Hello
|
||||
|
||||
A Client issues a Client Hello message when first establishing a connection.
|
||||
The Client Protocol Revision field specifies the Network Table protocol
|
||||
revision that the Client would like to use.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x01 - Client Hello
|
||||
|1 byte, unsigned; Message Type
|
||||
|
||||
|Client Protocol Revision
|
||||
|2 bytes, Unsigned 16-bit integer (big-endian). See
|
||||
<<def-protocol-revision,Protocol Revision>>.
|
||||
|
||||
|Client identity (name)
|
||||
|<<entry-value-string,String>>
|
||||
|===
|
||||
|
||||
[[msg-protocol-unsupported]]
|
||||
=== Protocol Version Unsupported
|
||||
|
||||
A Server issues a Protocol Version Unsupported message to a Client to inform it
|
||||
that the requested protocol revision is not supported. It also includes the
|
||||
most recent protocol revision which it supports, such that a Client may
|
||||
reconnect under a prior protocol revision if able.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x02 - Protocol Version Unsupported
|
||||
|1 byte, unsigned; Message Type
|
||||
|
||||
|Server Supported Protocol Revision
|
||||
|2 bytes, Unsigned 16-bit integer (big-endian). See
|
||||
<<def-protocol-revision,Protocol Revision>>.
|
||||
|===
|
||||
|
||||
[[msg-server-hello-complete]]
|
||||
=== Server Hello Complete
|
||||
|
||||
A Server issues a Server Hello Complete message when it has finished informing
|
||||
a newly-connected client of all of the fields it currently recognizes.
|
||||
Following the receipt of this message, a Client should inform the Server of
|
||||
any/all additional fields that it recognizes that the Server did not announce.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x03 - Server Hello Complete
|
||||
|1 byte, unsigned; Message Type
|
||||
|===
|
||||
|
||||
[[msg-server-hello]]
|
||||
=== Server Hello
|
||||
|
||||
A Server issues a Server Hello message in response to a Client Hello message,
|
||||
immediately prior to informing a newly-connected client of all of the fields it
|
||||
currently recognizes.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x04 - Server Hello
|
||||
|1 byte, unsigned; Message Type
|
||||
|
||||
|Flags
|
||||
a|1 byte, unsigned.
|
||||
|
||||
Least Significant Bit (bit 0): reconnect flag
|
||||
|
||||
* 0 if this is the first time (since server start) the server has seen the
|
||||
client
|
||||
|
||||
* 1 if the server has previously seen (since server start) the client (as
|
||||
identified in the <<msg-client-hello,Client Hello>> message)
|
||||
|
||||
Bits 1-7: Reserved, set to 0.
|
||||
|
||||
|Server identity (name)
|
||||
|<<entry-value-string,String>>
|
||||
|===
|
||||
|
||||
[[msg-client-hello-complete]]
|
||||
=== Client Hello Complete
|
||||
|
||||
A Client issues a Client Hello Complete message when it has finished informing
|
||||
the Server of any/all of the additional fields it recognizes that the Server
|
||||
did not announce.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x05 - Client Hello Complete
|
||||
|1 byte, unsigned; Message Type
|
||||
|===
|
||||
|
||||
[[msg-assign]]
|
||||
=== Entry Assignment
|
||||
|
||||
A Entry Assignment message informs the remote party of a new Entry. An Entry
|
||||
Assignment's value field must be the most recent value of the field being
|
||||
assigned at the time that the Entry Assignment is sent.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x10 - Entry Assignment
|
||||
|1 byte, unsigned; Message Type
|
||||
|
||||
|Entry Name
|
||||
|<<entry-value-string,String>>
|
||||
|
||||
|Entry Type
|
||||
|1 byte, unsigned; see <<entry-types,Entry Types>>
|
||||
|
||||
|Entry ID
|
||||
|2 bytes, unsigned
|
||||
|
||||
|Entry Sequence Number
|
||||
|2 bytes, unsigned
|
||||
|
||||
|Entry Flags
|
||||
|1 byte, unsigned; see <<entry-flags,Entry Flags>>
|
||||
|
||||
|Entry Value
|
||||
|N bytes, length depends on Entry Type
|
||||
|===
|
||||
|
||||
If the Entry ID is 0xFFFF, then this assignment represents a request from a
|
||||
Client to the Server. In this event, the Entry ID field and the Entry Sequence
|
||||
Number field must not be stored or relied upon as they otherwise would be.
|
||||
|
||||
[[msg-update]]
|
||||
=== Entry Update
|
||||
|
||||
An Entry Update message informs a remote party of a new value for an Entry.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x11 - Entry Update
|
||||
|1 byte, unsigned; Message Type
|
||||
|
||||
|Entry ID
|
||||
|2 bytes, unsigned
|
||||
|
||||
|Entry Sequence Number
|
||||
|2 bytes, unsigned
|
||||
|
||||
|Entry Type
|
||||
|1 byte, unsigned; see <<entry-types,Entry Types>>.
|
||||
|
||||
Note this type is only used to determine the length of the entry value, and
|
||||
does NOT change the stored entry type if it is different (due to an intervening
|
||||
Entry Assignment); Clients and Servers must ignore Entry Update messages with
|
||||
mismatching entry type.
|
||||
|
||||
|Entry Value
|
||||
|N bytes, length dependent on value type
|
||||
|===
|
||||
|
||||
[[msg-flags-update]]
|
||||
=== Entry Flags Update
|
||||
|
||||
An Entry Flags Update message informs a remote party of new flags for an Entry.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x12 - Entry Flags Update
|
||||
|1 byte, unsigned; Message Type
|
||||
|
||||
|Entry ID
|
||||
|2 bytes, unsigned
|
||||
|
||||
|Entry Flags
|
||||
|1 byte, unsigned; see <<entry-flags,Entry Flags>>
|
||||
|===
|
||||
|
||||
Entries may be globally deleted using the following messages. These messages
|
||||
must be rebroadcast by the server in the same fashion as the Entry Update
|
||||
message. Clients and servers must remove the requested entry/entries from
|
||||
their local tables. Update messages received after the Entry Delete message
|
||||
for the deleted Entry ID must be ignored by Clients and Servers until a new
|
||||
Assignment message for that Entry ID is issued.
|
||||
|
||||
[[msg-delete]]
|
||||
=== Entry Delete
|
||||
|
||||
Deletes a single entry or procedure.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x13 - Entry Delete
|
||||
|1 byte, unsigned; message type
|
||||
|
||||
|Entry ID
|
||||
|2 bytes, unsigned
|
||||
|===
|
||||
|
||||
[[msg-clear-all]]
|
||||
=== Clear All Entries
|
||||
|
||||
Deletes all entries. The magic value is required to be exactly this value
|
||||
(this is to avoid accidental misinterpretation of the message).
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x14 - Clear All Entries
|
||||
|1 byte, unsigned; message type
|
||||
|
||||
|Magic Value (0xD06CB27A)
|
||||
|4 bytes; exact value required (big endian)
|
||||
|===
|
||||
|
||||
[[msg-rpc-execute]]
|
||||
=== Remote Procedure Call (RPC) Execute
|
||||
|
||||
Executes a remote procedure. Intended for client to server use only.
|
||||
|
||||
The client shall provide a value for every RPC parameter specified in the
|
||||
corresponding RPC entry definition.
|
||||
|
||||
The server shall ignore any Execute RPC message whose decoding does not match
|
||||
the parameters defined in the corresponding RPC entry definition.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x20 - Execute RPC
|
||||
|1 byte, unsigned; message type
|
||||
|
||||
|RPC Definition Entry ID
|
||||
|2 bytes, unsigned
|
||||
|
||||
|Unique ID
|
||||
|2 bytes, unsigned; incremented value for matching return values to call.
|
||||
|
||||
|Parameter Value Length
|
||||
|N bytes, unsigned <<leb128>> encoded length of total number of bytes of
|
||||
parameter values in this message
|
||||
|
||||
|Parameter Value(s)
|
||||
|Array of values; N bytes for each parameter (length dependent on the parameter
|
||||
type defined in the <<rpc-definition,RPC entry definition>>)
|
||||
|===
|
||||
|
||||
[[msg-rpc-response]]
|
||||
=== RPC Response
|
||||
|
||||
Return responses from a remote procedure call. Even calls with zero outputs
|
||||
will respond.
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|Field Name |Field Type
|
||||
|
||||
|0x21 - RPC Response
|
||||
|1 byte, unsigned; message type
|
||||
|
||||
|RPC Definition Entry ID
|
||||
|2 bytes, unsigned
|
||||
|
||||
|Unique ID
|
||||
|2 bytes, unsigned; matching ID from <<msg-rpc-execute,RPC Execute>> message
|
||||
|
||||
|Result Value Length
|
||||
|N bytes, unsigned <<leb128>> encoded length of total number of bytes of result
|
||||
values in this message
|
||||
|
||||
|Result Value(s)
|
||||
|Array of values; N bytes for each result (length dependent on the result type
|
||||
defined in the <<rpc-definition,RPC entry definition>>)
|
||||
|===
|
||||
|
||||
[[rpc-operation]]
|
||||
== Remote Procedure Call (RPC) Operation
|
||||
|
||||
Remote procedure call entries shall only be assigned by the server.
|
||||
|
||||
Remote procedure call execute messages will result in asynchronous execution of
|
||||
the corresponding function on the server.
|
||||
|
||||
Client implementations shall not transmit an Execute RPC message and return an
|
||||
error to user code that attempts to call an undefined RPC, call one with
|
||||
incorrectly typed parameters, or attempts to make a call when the Client is not
|
||||
connected to a Server.
|
||||
|
||||
Remote procedure calls cannot be persisted.
|
||||
|
||||
[[rpc-definition]]
|
||||
=== Remote Procedure Call Definition Data
|
||||
|
||||
The data provided in the RPC definition entry consists of:
|
||||
|
||||
[cols="1,3"]
|
||||
|===
|
||||
|RPC Definition Version
|
||||
|1 byte, unsigned; always set to 1 for this version of the protocol.
|
||||
|
||||
|Procedure (Entry) Name
|
||||
|<<entry-value-string,String>>
|
||||
|
||||
|Number of Parameters
|
||||
|1 byte, unsigned (may be 0)
|
||||
|
||||
2+s|Parameter Specification (one set per input parameter)
|
||||
|
||||
|Parameter Type
|
||||
|1 byte, unsigned; <<entry-types,Entry Type>> for parameter value
|
||||
|
||||
|Parameter Name
|
||||
|<<entry-value-string,String>>
|
||||
|
||||
|Parameter Default Value
|
||||
|N bytes; length based on parameter type (encoded consistent with corresponding
|
||||
<<entry-values,Entry Value>> definition)
|
||||
|
||||
|Number of Output Results
|
||||
|1 byte, unsigned (may be 0)
|
||||
|
||||
2+s|Result Specification (one set per output)
|
||||
|
||||
|Result Type
|
||||
|1 byte, unsigned; <<entry-types,Entry Type>> for value
|
||||
|
||||
|Result Name
|
||||
|<<entry-value-string,String>>
|
||||
|===
|
||||
Reference in New Issue
Block a user