VRML+
Scalable Reliable Datagram Protocol
The Scalably Reliable Datagram Protocol SRDP was designed to fill a gap between the lightness and efficiency of UDP and the robustness of TCP.
In a lot of situations involving communications between a number of participants, we need a protocol that allows messages to be sent from peer to peer or between client and server without the overhead of opening a TCP session . In many of these cases, UDP works fine, however UDP does not guarrantee delivery.
SRDP is designed to give the application the ability to decide how much reliability it wants. The reliability is achieved by sending the message a selectable number of times until an acknowledgement is received.
A number of design criteria govern some of the choices here.
- SRDP must scale to many thousands of simultaneous connections.
- SRDP must be capable of being implemented simply, but also allow for future optimisation
- SRDP should not require ANY changes to underlying TCP stacks.
- SRDP should be able to work through proxy servers on firewalls.
- SRDP should generate minimal network overhead
- SRDP should smoothly degrade from networks with 100% delivery to 0% delivery.
- SRDP should be easily retrofitted to existing network applications.
SRDP details
SRDP operates over UDP, it provides a simple layer between the application and UDP. A typical call to SRDP looks like:
srdp_send(DestnAddr,bytes,size,SourceAddr, repeats, timeout,flags)
where:
- sockaddr_in DestnAddr
- The destination IP address and port, as built by traditional techniques using gethostbyname for UDP or TCP
- Uint16 size
- Number of bytes to send (max 548 set by limits on UDP packets)
- char * bytes
- The bytes to send in the packet
- sockaddr_in SourceAddr
- The source IP address and port
- Uint8 Repeats
- The number of times to send the packet - 0 means until received, but beware of endless repeats on dead destinations.
- time_t timeout
- The time to wait between retries, 0 means let the library decide
- Unit8 flags
- A bit field of service requests, see flags
SRDP takes the following actions, best expressed through pseudo-code:
Construct a srdp_packet data structure (see srdp_packet
Note the PacketId is the next increment of packetId
Call UDP to Send the packet to the destination (see data_on_wire
if timeout != 0
RetryTime=time_now+timeout
else
RetryTime calculated by heuristics (see optimisation
Add srdp_packet to srdp_sent_queue in order of retry time.
Adjust timer to RetryTime of first packet on queue.
At the receiving end, a UDP packet is received, and the receiver:
Parse the UDP data into a srdp_packet
If the top bit of the PacketId is set, its a acknowledgement
Construct an acknowledgement packet
set the PacketId to that of the received packet, with the top bit set.
Send that packet back to the SourceAddr
Pass the received packet up to the receiver.
There is a little hand-waiving here,
but it should be no different from handling UDP
Back at the Source Addr, the acknowledgement is received.
Extract the PacketId
if the top bit is clear, its not an acknowledgement, its a received packet
Locate the PacketId in the srdp_sent_queue,
typically it will be near the beginning,
so there is probably no need for a binary tree etc
Unqueue that packet from the srdp_sent_queue
Delete the packet and free up any memory used for it
Delete the acknowledgement and free up any memory used for it
If the packet was the first in the queue,
then readjust timer to RetryTime of first packet in queue
If the SRDP application is clever,
it can adjust its heuristics based on the time the packet was
sent, and the time the ACK was received.
If the timer expires before an acknowledgement was received
While (the first packet in the queue has a RetryTime before time_now)
Resend packet to the DestnAddr
Adjust RetryTime based on Delta_Time and time_now
Requeue packet based on RetryTime
Set timer based on RetryTime of first packet in queue
Data structures or classes
srdp_packet
-
Note this would typically be implemented as a string, with appropriate methods to access the elements, in order to avoid copying data. This data structure is not mandated by the specification, but is a usefull way to think about the functionality described here.
- Uint16 PacketId
- The sequence number of the packet
- sockaddr_in SourceAddr
- Host and port of source
- sockaddr_in DestnAddr
- Host and port of destn
- time_t Time
- On the sending end this is the time to retry the message
- On the receiving end, this is the time the message was retrieved
- time_t Delta_Time
- On the sending side, this is the time to wait between retries
- On the receiving side it currently has no meaning.
- char* Bytes
- The bytes received, this MAY contain NULLs terminated by end of packet
- UInt16 Size
- The length of the bytes following
Data on wire
Packet
This is the data in the UDP packet, which I do not believe has destination or source addresses in it?
- CommandType[1]
- A one byte fixed value TBD so that SRDP can co-exist
with our other protocols on the same port.
- Packet Id[2]
- The id of the packet as allocated by the sender
- Flags[1]
- Flags including SRDP_DONTDUPLICATE and SRDP_ORDER
- Bytes[Size]
- "Size" bytes of data (which may contain nulls) terminated by end of packet
Acknowledgement
- CommandType[1]
- A one byte value TBD indicating an SRDP acknowledgement
- Packet Id[2]
- The id of the packet being responded to, top-bit set
Flags
The flags to srdp_send specify service requests, these may or may not be implemented by all implementations, srdp_send should return SRDP_NOTIMP for services requested, but not implemented.
The following flags make sense.
- SRDP_DONTDUPLICATE
- Don't allow duplicate packets to be received, this can occur if the resent packet, and the acknowledgement cross in the network. This is tricky, because it relies on the receiver keeping a queue of received packets which could get large, this may never be implemented.
The second packet is sent with the same ID, there are three possible ways of dealing with this.
- Keep a list of recently received IDs, and discard duplicates
- Don't use SRDP for protocols which are really worried by packets arriving twice
- Tackle it at a higher level, i.e. something in the data prevents duplicates
- SRDP_ORDER
- This requires that packets are received in the order sent.
Packets can be mis-ordered if an early packet is lost and resent AFTER a later packet.
The receiver will get, and pass on, the packets in the wrong order, there are three ways around this.
- The sender only allows a maximum of one packet in the srdp_sent_queue per receiver, keeping a seperate queue of packets that are waiting.
- Dont use SRDP for protocols which are really worried about misordering.
- Tackle it at a higher level
Optimisation
While this is not going to be in early implementations, there is a simple way to optimise,
the library maintains a record of IP addresses, along with the maximum time between sending the packet, and receiving the acknowledgement, this can be used to tune the retry time, so that lost packets to fast/close hosts are resent quickly, while the network isn't flooded with unneccessary retries to slow/distant hosts.
Proxies
To handle this through a Proxie, there are two solutions that will make sense depending on the firewall configuration.
UDP
All SRDP packets are sent to the Proxy via UDP, the proxy, looks at the DestnAddr field, and routes based on this, for this to be supported, we have to use the SendAddr field, and can't use such a field from the UDP header (should it exist ??). The Proxy only has to look at the Addr and Port fields which are in the same place for Regular and Acknowledgement packets. The client does the queueing and resending.
TCP
SRDP is replaced with a layer that opens a TCP connection to the Proxy, the packets can be sent with exactly the same format, the SourceAddr isn't really needed, but is probably not worth removing since the connection to the proxy is typically on a fast bandwidth. The Proxy implements SRDP, and does the retries from there.
SOCKS
There is probably a way to do this with SOCKS, but I'm not familiar with it (any reference appreciated)
Packet size limitation
At this time SRDP will not support packets that have to be fragmented to be sent over the network, this requires a significant overhead, both in terms of code, and in the protocol. This limits the size of data to:
- 576
- Min IP datagramsize
- - 20
- IP header size
- - 8
- UDP header size
- - 16
- header fields from SRDP
- = 532
Acknowledgements
SRDP draws heavily on ideas from ARDP. Written by Cliff Neuman of Information Sciences Institute, it provides similar functionality to SRDP for situations requiring reliable query-response type interactions.
Worlds Inc VRML+ Team
Alan Steremberg <alans@core.worlds.net>
Jeff Close <close@halcyon.com>
Kyle Hayes <kyle@core.worlds.net>
Mitra <mitra@mitra.biz>
All contents Copyright © 1995 Worlds Inc. Reproduction for
personal use is permitted. All other uses are prohibited without the
formal authorization of Worlds Inc., Worlds, Worlds Chat, AlphaWorld, VRML+, Internet Worlds Fair, LifeForms, Worlds Class Builder and It's
Your World are all trademarks of Worlds Inc.
Web Problems?