This chapter provides a detailed specification for the TCP/IP Socket Transport and describes how clients use the transport to communicate with HIS. It contains these sections:
· Transport Overview
· Connection Handshake
· Protocol Negotiation
· Error Handling
Transport Overview
The TCP/IP Socket Transport provides a high-performance bi-directional communications channel between clients and HIS. This channel is persistent in that the connection remains open for the duration of client connectivity. It also maintains state in that once a client is connected and identified this information need not be retransmitted unless a new connection is made.
This transport incurs very little overhead when sending messages to or receiving messages from a client. Each message is framed with a short header that consists of a 4-byte boundary token, a 1-byte protocol index, and finally a 4-byte length field.
Message Boundary
The 4-byte message boundary marks the start of every message sent from the client or server. The boundary token will always be the 4 ASCII characters '~', '!', 'O', and 'M'. Even though this group of characters could occur naturally within the message contents section, there is no need for the client or server to escape or encode it. The boundary is used to ensure each message frame is coherent. After reading the total bytes of the previous message contents section, the reader should ensure the next 4 bytes matches the boundary prior to continuing to process the message. If the boundary isn't found, a network or sender error has occurred causing the receiver to generate and send an ERROR message to the sender; followed by termination of the socket.
Protocol Index
When HIS or client receives a message, it needs to be able to determine which protocol the message is destined for without having to process the message contents. The protocol index uniquely identifies a protocol type and version for this HIS instance. The client can determine the index of each protocol and version during the protocol negotiation phase.
Although not technically a protocol, the messages belonging to this transport for handshaking, protocol negotiation, teardown, and error handling always occupy protocol index 0. The most current direct client protocol version supported by the HIS instance always occupies protocol index 1. This allows clients who only use the current direct client protocol to skip the process of protocol negotiation.
Content Length
The 4-byte content length field indicates the following n bytes will contain the contents of the message. The length field is delivered in big endian format with bit 0 indicating value sign. The 32-bit integer is signed to support those technologies that do not inherently have unsigned integers such as Java.
Example Message Header
B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 | B8 |
'~' | '!' | 'O' | 'M' | 00000001 | 00000000 | 00000000 | 00000000 | 11111111 |
Message Boundary | Direct | Indicates 255 bytes of content |
The above example 9-byte header shows the standard message boundary "~!OM" occupying the first 4 bytes. The next byte identifies which protocol this message belongs to. The value of 1 is used to select the direct client protocol. The last 4 bytes are the length field indicating the following 255 bytes will be message content.
Message Contents
Outside of the initial handshake and protocol negotiation messages, the contents of the message are not defined by this transport. The byte encoding of the message content is protocol specific and must be handled as part of the protocol specification. The message contents will be delivered to the protocol handler in raw byte array form.
Although the transport supports messages with up to 231 bytes of content, it is highly recommended that most messages are as brief as possible. Messages should contain less than 1K of content as to fit within a single network packet when feasible.
Connection Lifecycle
All client connections using this Transport follow the same lifecycle. The client opens a socket connection to HIS. The connection or session enters the handshake phase that includes party identification and possibly authentication. Once all parties are identified and authenticated, the connection enters the protocol negotiation phase.
The client must confirm that the HIS instance supports the message protocol it desires to use. Since the Direct client protocol is always available, clients not using other protocols can skip the protocol negotiation phase entirely. Although clients may use multiple protocols over the same socket connection, most clients will use a single protocol for the session's duration.
Once the handshake and protocol negotiation phases are complete, the client may begin sending protocol messages to HIS. Once a session is finished, the client may explicitly end the session with the transport teardown message or simply release the socket connection.
Connection Handshake
The handshake phase begins immediately following a client opening a socket to HIS. HIS will deliver a HELLO message to the client that contains information about the HIS instance.
Server HELLO Message Header
B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 | B8 |
'~' | '!' | 'O' | 'M' | 00000000 | xxxxxxxx | xxxxxxxx | xxxxxxxx | xxxxxxxx |
Message Boundary | Transport | Length of content |
The standard message boundary is used for all messages. The protocol index for Transport messages (handshake, protocol negotiation, and teardown) is always 0. The length of the server HELLO message is variable depending on the information provided.
Server HELLO Message Contents
The standard HELLO message contains a JSON structure that provides clients with information about the HIS instance and indicates if the client must authenticate with the server.
{
"type": "HELLO",
"server-info":
{
"name": "[instance-name]"
},
"auth-required": "[true/false]"
}
Client HELLO Message Header
B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 | B8 |
'~' | '!' | 'O' | 'M' | 00000000 | xxxxxxxx | xxxxxxxx | xxxxxxxx | xxxxxxxx |
Message Boundary | Transport | Length of content |
The standard message boundary is used for all messages. The protocol index for Transport messages (handshake, protocol negotiation, and teardown) is always 0. The length of the client HELLO message is variable depending on the information provided.
Client HELLO Message Contents
The standard client HELLO message contains a JSON structure that provides HIS with information about the client.
{
"type": "HELLO",
"client-info":
{
"id": "[client-id]",
"name": "[client-name]"
}
}
Protocol Negotiation
Clients that wish to use one of the managed message protocols must first ensure the protocol is supported and the proper version is available. This phase is unnecessary for clients using the direct message protocol. The client begins by sending the PROTOCOLS client transport message to the server to request the list of available protocols and versions. The server responds with the PROTOCOLS server transport message containing the protocol information.
Client PROTOCOLS Message Header
B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 | B8 |
'~' | '!' | 'O' | 'M' | 00000000 | 00000000 | 00000000 | 00000000 | 00010100 |
Message Boundary | Transport | Length of content (20) |
The standard message boundary is used for all messages. The protocol index for Transport messages (handshake, protocol negotiation, and teardown) is always 0. The length of the client PROTOCOLS message should always be 20 bytes. There is no need to pretty print the message contents on the wire.
Client PROTOCOLS Message Contents
The standard client PROTOCOLS message contains a JSON structure that simply indicates the server should provide the client with the list of supported protocols and versions.
{
"type": "PROTOCOLS"
}
Server PROTOCOLS Message Header
B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 | B8 |
'~' | '!' | 'O' | 'M' | 00000000 | xxxxxxxx | xxxxxxxx | xxxxxxxx | xxxxxxxx |
Message Boundary | Transport | Length of content |
The standard message boundary is used for all messages. The protocol index for Transport messages (handshake, protocol negotiation, and teardown) is always 0. The length of the server PROTOCOLS message is variable depending on the information provided.
Server PROTOCOLS Message Contents
The standard PROTOCOLS message contains a JSON structure that provides clients with information about which protocols and versions are available from this HIS instance. Three pieces of information are provided for each protocol and version pair supported by this HIS instance: protocol index, protocol type, and protocol version. Although the protocols are delivered in a JSON array, the protocol index is explicitly supplied because protocols and protocol versions may not remain active during the lifecycle of the HIS instance so there may be missing indexes causing the protocol index field to not match its position within the JSON array.
{
"type": "PROTOCOLS",
"protocols":
[
{
"index": "0",
"type": "com.openmethods.ep.network.transport.socket",
"version": "4.0.0"
},
{
"index": "1",
"type": "com.openmethods.ep.network.protocol.direct",
"version": "4.0.0"
},
{
"index": "[protocol-index]",
"type": "[protocol-id]",
"version": "[version-number]"
},
…
]
}
Error Handling
An error can occur during message processing for several reasons:
· Client provided no credentials even though server requires authentication
· Client provided credentials cannot be authenticated
· Client sent a message using an unbound protocol index value
· Client sent a message with a negative content length
· Message boundary mismatch
· Client sent a message prior to the server HELLO message
In all cases, an ERROR message is generated and sent to the client. The message contains details as to why the error was raised. Immediately following the delivery of the ERROR message, the server must close the network socket.
ERROR Message Header
B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 | B8 |
'~' | '!' | 'O' | 'M' | 00000000 | xxxxxxxx | xxxxxxxx | xxxxxxxx | xxxxxxxx |
Message Boundary | Transport | Length of content |
The standard message boundary is used for all messages. The protocol index for Transport messages (handshake, protocol negotiation, and teardown) is always 0. The length of the ERROR message is variable depending on the information provided.
ERROR Message Contents
The standard ERROR message contains a JSON structure that provides details about the error.
{
"type": "ERROR"
"code": "[error-code]",
"message": "[readable-error-text]",
"context": "[stack-trace-if-available]"
}
Connection Tear Down
If the client or server wishes to gracefully disconnect from the other, a BYE message is sent prior to ending the connection. The receiving party should begin the connection tear down process and respond with a BYE message of their own.
BYE Message Header
B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 | B8 |
'~' | '!' | 'O' | 'M' | 00000000 | 00000000 | 00000000 | 00000000 | 00001110 |
Message Boundary | Transport | Length of content |
The standard message boundary is used for all messages. The protocol index for Transport messages (handshake, protocol negotiation, and teardown) is always 0. The length of the Bye message is always 14 bytes.
BYE Message Contents
The standard Bye message contains a JSON structure that indicates the type of message.
{
"type": "BYE"
}