|
The Kiwi Reliable Delivery Protocol (KRDP) |
Top Previous Next |
|
Background:
The Kiwi Reliable Delivery Protocol was designed to solve the problem of losing data when a TCP connection is broken due to a network failure.
KRDP uses the TCP protocol as the underlying transport. This ensures that each packet sent is sequenced and acknowledged when received. The TCP protocol on the receiving system handles the packet order and ensures that any missing packets are resent.
The problem:
TCP works well as a reliable transport when the connection can be opened and closed cleanly. During a TCP close handshake, any outstanding packets are usually received and acknowledged before the connection is closed.
However, if a break in the network occurs during message sending, the sender will continue to send packets until the TCP window size is reached. When no acknowledgement is received after a timeout period, the Winsock stack will fire a timeout event. When this happens, it is not possible to know exactly which message (or part message) was last received and acknowledged by the remote end. Any data that was sitting in the Winsock stack's buffer will be lost. Depending on the TCP window size and the speed of the data being sent, this could be hundreds of lost messages.
The solution:
KRDP works by adding another acknowledgement and sequencing layer over the top of the TCP transport. KRDP wraps each syslog message with a header which contains a unique sequence number. The KRDP sender keeps a local copy of each message it has sent. The KRDP receiver periodically acknowledges receipt of the last KRDP wrapped syslog message it has received. The KRDP sender can then remove all locally stored messages up to the last acknowledged sequence number. When the connection is broken and re-established, the receiver informs the sender which messages need to be resent.
Each KRDP sender is identified with a unique connection name. This allows the sender and receiver to re-establish the same session and sequence numbers, even if the IP address or sending port of the sender has been changed due to DHCP etc.
Unique message sequencing:
Each KRDP message is identified with a unique sequence number. The sequence starts at 1 and increments in steps of 1 up to 2147483647 (2 billion), then wraps around to 1 again. The message number 0 is used to indicate that the system does not know the last sequence number and that it has had to assume a fresh start. If this occurs, both the sender and receiver will log an error to note the lost messages.
Dealing with international characters:
Unicode allows the mapping of all international character sets into a known byte sequence. The mapping of non US-ASCII characters requires the use of more than a single byte per character. The most commonly used way of sending these multi-byte characters over TCP is to use UTF-8 encoding. The KRDP sender will encode the syslog messages as UTF-8 and the KRDP receiver will decode them back to Unicode again.
The KRDP message format:
Sender (S) Receiver (R)
Message Types (MsgType):
00 = SenderID 01 = ReceiverResponse 02 = Sequenced message 03 = Message acknowledgement 04 = Receiver KeepAlive 99 = Error message
Message format:
KRDP AA 0000000000 Message<CR>
KRDP = Unique tag Space (ASCII 32) AA = Msg type (as above) Space (ASCII 32) 0000000000 = Sequence number 0 to 2147483647 Space (ASCII 32) Message = UTF-8 encoded message text <CR> = Carriage return character ASCII 13 to indicate end of message stream
Sequence of events:
S connects via TCP S sends first ID packet (MsgType 00) R responds with ReceiverResponse message (MsgType 01) S sends sequenced messages (MsgType 02)
Rules:
Message formats:
MsgType 00 (Version and SenderID) KRDP 00 PV UniqueKey<CR> The unique key identifies the channel and is used to synchronise the message numbers PV = Protocol Version to use. 01 = KRDP Reliable/Acknowledged Unique key format is free form. An example would be: "IP=192.168.1.1, Host=myhost.com, ID=Instance1" Or, just: "Instance1" Since the receiver might already have an "Instance1" name from another source, the first UniqueKey would be better. Use as much information to uniquely describe the source of the messages
MsgType 01 (ReceiverResponse message) KRDP 01 0000000000 Listener ID<CR> Message number is 10 digit number 0000000000 to 2147483647
MsgType 02 (Sender Message content) KRDP 02 0000000000 Message content<CR> Message number is 10 digit number 0000000000 to 2147483647
MsgType 03 (Receiver ACK) KRDP 03 0000000000 ACK<CR> Message number is 10 digit number 0000000000 to 2147483647 Message number indicates the next sequence number it expects to receive ACK messages are sent at a maximum rate of once every 200ms
MsgType 04 (Keep alive) KRDP 04 0000000000 KeepAlive<CR> Message number is 10 digit number 0000000000 to 2147483647 Message number = Next expected message number If being sent by Sender, MsgSeq should be set to 0 If being sent by Receiver, MsgSeq should be set to next expected message number
MsgType 99 (Error) KRDP 99 0000000000 0000 Error message here<CR> Message number is 10 digit number 0000000000 to 2147483647 Message number indicates which message caused the error if any. Set to zero (0) if not related to a message number 0000 = Error number (0000 to 9999) Error message can be any text
|