mr-udp

name=MR-UDP | version= 2.0 | accountable=Marcos Roriz | depdency= [[MR-UDP]]

MR-UDP

MR-UDP is an extended and optimized version of Reliable UDP (R-UDP) that is used to communicate with mobile nodes. It extends R-UDP protocol with mobility-tolerating features, such as the ability to handle intermittent connectivity, Firewall/NAT traversal and robustness to switching of IP addresses or network interfaces (e.g. Cellular to WiFi, and vice-versa). By using UUID to address the connection and packages rather than IP, MR-UDP can handle handovers. Current version (2.0) includes a series of optimizations for better throughput and confiability.

In general, there are few cases for using MR-UDP directly. In almost all instances, you should use ClientLib a higher-level wrapper library that makes MR-UDP easier to use and interacts better with the rest of ContextNet components.

MR-UDP is implemented in Java, and enhances a publically available Reliable UDP implementation named Simple R-UDP. The programming interface provides ReliableClientSocket and ReliableServerSocket classes, which extend the conventional Java Socket’s programming interface, with the well-known Socket, ServerSocket, InputStream, and OutputStream classes. MR-UDP has several features inherited from Reliable UDP, such as: acknowledgment of received data packets; in-order packet delivery with selective retransmission of lost packets, and over-buffering.

Since MR-UDP implements the well-known Java Socket API its usage is similar to Java RAW Socket. To create a client, please create a new ReliableSocket with the server host and port. After that, you can use Java Socket operations. For example, to send a message you can retrieve and write to the socket OutputStream.

HelloClient.java
public class HelloClient {
 
  public static void main(String[] args) throws Exception {
    String host = "127.0.0.1";
    int port = 5500;
 
    ReliableSocket clientSocket = new ReliableSocket(host, port);
    ReliableSocketOutputStream outputStream = (ReliableSocketOutputStream) clientSocket.getOutputStream();
    PrintWriter outputBuffer = new PrintWriter(outputStream);
 
    outputBuffer.println("JAVA Hello World MR-UDP!");
    outputBuffer.flush();
    Thread.sleep(10*1000);
    clientSocket.close();
  }
}

Developers can also configure the protocol parameters. To do so, developers needs to extend the ReliableSocketProfile class and pass an instance of this profile when initiating the connection (on the ReliableSocket constructor). The parameters in this class follow the RUDP RFC guidelines. In the following paragraph we will cover a few of these parameters.

* MAX_SEGMENT_SIZE (Default: 256 bytes); 
 The maximum number of octets that can be received by the peer sending the SYN segment.  Each peer may specify a different value.
 
* MAX_OUTSTANDING_SEGS (Default: 3 segments);
 The maximum number of segments that should be sent without getting an acknowledgment.  This is used by the receiver as a means of flow control.

* MAX_RETRANS (Default: 10 retransmissions);
 The maximum number of times consecutive retransmission(s) will be attempted before the connection is considered broken.  The valid range for this value is 0 to 255.  A value of 0 indicates retransmission should be attempted forever.

In general, MR-UDP architecture follows closely the R-UDP architecture. However, the implementation has diverged drastically from R-UDP. In 2.0, we did major modifications in internals parts, specifically on networking, threading and scheduler, while not breaking the protocol interfaces. All UDP send and receive primitives are concentrated in an asynchronous scheduler AsyncScheduler.

In addition, we switched from blocking network primitives (Java IO) to non-blocking (Java NIO). Originally, when a connection was created MR-UDP (and R-UDP) it started a background receive and send thread. This premise became troublesome to scale for the server part (our Gateway) when we need to handle a large number of connections. By using Java NIO we can simplify our code to use only one thread to handle the networking. The Java NIO Select primitive enables us to monitor the connections using a single thread, as illustrated below.

Java NIO

When a connection received something it will trigger the select handler, which will process the receiving data. When sending a message, the connection will queue the message in the scheduler thread pool. This enable us to control the sending in an entire part. Not only these change simplified the codebase, the code is isolated and simpler, but also enabled the server to scale to a higher number of connections.

The MR-UDP protocol can be summarized in a state machine for receiving and sending (displayed bellow) messages. The ReliableSocketServer starts on the receiver thread state. It receives a port and a connection profile, as a result it starts a clean connection hash table and start a listening UDP socket on the specified port. When it receives a SYN segment the server transits to the “negotiate and save” endpoint state.

Using the receiving segment, the server extract the client address, UUID, and connection parameters. In addition, the server will send a SYN segment to the client. Then, the server transits to the “map connection” state, where it validates the client UUID. If the server already has a client with that UUID it changes the client endpoint to the IP received in the SYN segment and then transit to the listening state. However, if the server does not have a client with that UUID, it will create and associate a new UDP socket with this combination (client UUID, endpoint) and it will transit back to the negotiation state. When the client respond with an ACK segment, the server will start listening the receiving thread for this client and go back to the “Receiver Thread” state.

Finally, when the sever receives data, i.e., DAT segments, it checks to see if the package is in order for that connection. If it is, the server trigger the receive routine of the application. However, if it is not, the server send save the package in a buffer (of size MAX_OUT_OF_SEQUENCE) and send an ACK segment with the latest known sequence number.

Receiver FSM


The client state machine is similar to the server automata. The primary difference is that the client start in the “negotiate and save” state. In this state, the client start the connection with the server information (address and port) using a given connection profile. It sends a SYN segment with the connections parameters and waits on this state for a corresponding SYN reply from the server. When the client this message it sends an ACK message to finish the handshake. After that, the client transit to the “open” state.

When an MRUDP application sends a message to the server, the message is divided in a sequence of DAT segments of size MAX_SEGMENT_SIZE. For each segment, the protocol verify if the unack queue is empty, if it is not, the client cannot send additional segments. If the unack queue is empty the protocol queues the segment in the unack queue and sends to the server in a conventional UDP socket. Sender FSM

MR-UDP: Yet another Reliable User Datagram Protocol, now for Mobile Nodes L.D. Silva, M. Endler, M. Roriz, MR-UDP: Yet another Reliable User Datagram Protocol, now for Mobile Nodes,

Link: http://www.lac.inf.puc-rio.br/publications/mr-udp-yet-another-reliable-user-datagram-protocol-now-mobile-nodes

  • mr-udp.txt
  • Last modified: 2017/07/21 03:08
  • (external edit)