Package edu.rit.m2mp is the API for the Many-to-Many Protocol (M2MP).

Section 1 briefly introduces the concepts of M2MP and describes the architecture of the M2MP Layer. Section 2 describes how to configure the M2MP Layer. Section 3 describes how to run the M2MP Daemon. Section 4 describes how to write code using the M2MP Library. Section 5 describes the format of M2MP packets and describes how M2MP packets are processed.


Table of Contents

1. M2MP Concepts
2. Configuring the M2MP Layer
3. Running the M2MP Daemon
4. Working with the M2MP Library
5. M2MP Packet Format and Processing


1. M2MP Concepts

Assumptions

Intended particularly for the wireless proximal ad hoc networking environment, M2MP's design is based on these assumptions:

  1. Messages are not sent to particular device addresses. Consequently, devices can enter and leave the network in an ad hoc fashion without having to maintain any routing tables.
     
  2. Messages are broadcast to all nearby devices. M2MP assumes it is using a broadcast communication medium, like a wired Ethernet or a wireless Ethernet. Every device in a proximal group of devices -- every device on the same wired Ethernet segment, or every device in radio range in a wireless Ethernet -- receives every transmission from every device. Therefore, at the data link level it's just as easy to deliver a message to all devices as to one device.
     
  3. Message delivery is mostly reliable. Most of the time, a message broadcast by one device is received by all the other devices. However, on rare occasions a message broadcast by one device is not received by some or all of the other devices.
     
  4. Packets are not reordered in the communication medium. While the broadcast communication medium may occasionally fail to deliver certain packets to certain devices, the packets that do get through are delivered in the same order at every device.
     
  5. A message's relevancy is determined by its contents. A device decides which incoming messages to process by examining the initial bytes of each message.

Message Transfer

When an application on one device sends an M2MP message, the application writes a stream of bytes with the message's contents to the M2MP Layer. The M2MP Layer breaks the byte stream into a sequence of fragments, wraps each fragment in a packet, and broadcasts each packet. On the receiving device, the M2MP Layer reassembles the packets into messages and passes the messages up to the application. See "M2MP Packet Format and Processing" for further information about the M2MP packets.

To receive incoming messages, an application must register one or more message filters with the M2MP Layer. Each message filter has a message prefix, a fixed byte string. If an incoming message's initial bytes match the message prefix of a registered message filter, the M2MP Layer passes the message up to the application that registered the message filter. Otherwise, the M2MP Layer discards the message, and the application never sees it. An application that uses M2MP, such as M2MI, designs the contents of its M2MP messages to take advantage of M2MP's message filtering capability and weed out irrelevant messages before they ever reach the application.

If a failure occurs in the middle of an incoming message, such as a lost packet, the M2MP Layer will time out waiting for the proper packet to arrive. If the timeout occurs, the M2MP Layer abandons the message and signals an exception to the application reading the message. The M2MP Layer does not retransmit packets.

Retransmitting lost packets is unnecessary, and abandoning the message is acceptable, because M2MP assumes the proximal network is mostly reliable. Recovery from an occasional message loss can be done at the application level. Indeed, the messaging layer should not be expected to provide end-to-end delivery or ordering guarantees. This considerably simplifies M2MP.

M2MP Layer Architecture

Ideally, M2MP would be implemented in the platform operating system (as TCP/IP is), and there would be system calls and programming language APIs for accessing the M2MP Layer. However, at present M2MP is implemented at the user level, not in the operating system. This means that users must be aware of the M2MP Layer's architecture to a certain extent in order to run M2MP-based applications, such as M2MI-based applications.

On each device, the M2MP Layer can be configured in two different ways. Figure 1 shows the more common alternative.


Figure 1. Multiple M2MP application processes on a device

Here there are one or more M2MP-based applications running in different processes on the same device. In this case, an additional process, the M2MP Daemon process, must also be running on the device. Each application process has an instance of the M2MP Layer. Each M2MP Layer uses a "daemon channel" to communicate with the M2MP Daemon process. The M2MP Daemon process in turn uses another channel to communicate with other devices over the external network. Figure 1 shows the M2MP Daemon process using a "UDP multicast channel" to communicate with other devices using UDP multicast datagrams. To use a different kind of external network, M2MP can be configured to use a different kind of channel.

An M2MP message sent from an application process within the device arrives at the M2MP Daemon process via the daemon channel. The M2MP Daemon process then forwards a copy of the message to every other application process within the device, and the M2MP Daemon process also broadcasts a copy of the message on the external network. An M2MP message sent from an application process in another device arrives at the M2MP Daemon process via the channel connected to the external network. The M2MP Daemon process then forwards a copy of the message to every application process within the device. In this way, an M2MP message gets broadcast everywhere except to the process that sent it.

Figure 2 shows the other way to configure the M2MP Layer. If there is only one M2MP-based application process on a device, then the M2MP Daemon process is not needed, and the application process's M2MP Layer can communicate directly with the external network.


Figure 2. A single M2MP application process on a device


2. Configuring the M2MP Layer

Both the M2MI Layer and the M2MP Layer are configured by means of a "device properties file" containing a device ID value. Typically, the device properties file is named "device.properties" and resides in the home directory of your account. With the device properties file located in your home directory, every application that runs in your account will use the same device ID. Another possibility is to put the "device.properties" file in a subdirectory; then every application that runs in that subdirectory will use that file to get the device ID (instead of the file in your home directory if any). See class DeviceProperties for further information about where the device properties file can be located.

Here is the typical recommended contents of the device properties file. If you use this example, be sure to change the value of the edu.rit.device.id property.

# Device Properties File

# Globally unique device ID (hexadecimal integer, 000000000000 .. 3FFFFFFFFFFF)
edu.rit.device.id = 00087443BC87

The meaning of the above setting is as follows. See class DeviceProperties for further information about the possible property settings.

The M2MP Layer is also configured by means of an "M2MP properties file" containing a number of configuration settings. Typically, the M2MP properties file is named "m2mp.properties" and resides in the home directory of your account. With the M2MP properties file located in your home directory, every application that runs in your account will use the same configuration for the M2MP Layer. Another possibility is to put the "m2mp.properties" file in a subdirectory; then every application that runs in that subdirectory will use that file to configure the M2MP Layer (instead of the file in your home directory if any). See class M2MPProperties for further information about where the M2MP properties file can be located.

Here is the typical recommended contents of the M2MP properties file. A copy of this file is included in the M2MP Library (m2mp.properties).

# M2MP Properties File

# Message timeout, milliseconds (decimal integer > 0)
edu.rit.m2mp.messagetimeout = 5000

# Flow control timeout, milliseconds (decimal integer > 0)
edu.rit.m2mp.flowtimeout = 100

# Packet redundancy (decimal integer > 0)
edu.rit.m2mp.redundancy = 2

# ReceiverThread debug level (integer)
# 0 = Don't print
# 1 = Print exception stack traces
# 2 = Print exception stack traces and debug messages
edu.rit.m2mp.debug.ReceiverThread = 0

# Packet debug level (integer)
# 0 = Don't print
# 1 = Print packet arrivals and departures
# 2 = Print packet arrivals and departures, including packet contents
edu.rit.m2mp.debug.packets = 0

# Message filter debug level (integer)
# 0 = Don't print
# 1 = Print message filter additions and removals
# 2 = Print message filter additions and removals including message prefixes
edu.rit.m2mp.debug.messagefilters = 0

# M2MP Layer control panel (integer)
# 0 = Don't display control panel
# 1 = Display control panel
edu.rit.m2mp.debug.controlpanel = 0

# M2MP Daemon process's port number (0 if no M2MP Daemon process)
edu.rit.m2mp.daemon.port = 5678

# M2MP channel implementation class name
edu.rit.m2mp.channel.class = edu.rit.m2mp.udp.UDPMulticastChannel

The meanings of the above settings are as follows. See class M2MPProperties for further information about the possible property settings.

The above M2MP properties file is configured for the typical case where M2MP client processes communicate with M2MP client processes in other devices via an external network. If M2MP client processes will never communicate with other devices, change the M2MP channel class setting as follows:
 
    edu.rit.m2mp.channel.class = edu.rit.m2mp.NullChannel

The above M2MP properties file is also configured for the typical case where multiple M2MP client processes are running in the same device and the M2MP Daemon process is used to route M2MP messages among the client processes as well as the external network. If only one M2MP client process will ever run on the device, then the M2MP Daemon process is not needed. In that case, change the M2MP Daemon port setting as follows:
 
    edu.rit.m2mp.daemon.port = 0
 
The M2MP Layer will then communicate directly with the external network using an instance of the channel class specified by the edu.rit.m2mp.channel.class property.


3. Running the M2MP Daemon

If the M2MP Layer is configured to use the M2MP Daemon (property edu.rit.m2mp.daemon.port is not 0), then you must run the M2MP Daemon in a separate process before running any M2MP- or M2MI-based applications. To run the M2MP Daemon process, type this command:
 
    java edu.rit.m2mp.Daemon


4. Working With the M2MP Library

If you write applications using M2MI, you never need to work with the M2MP Library directly. For those who want to use M2MP without using M2MI, this section gives an overview of how to write M2MP-based applications using the M2MP Library. For more detailed information, refer to the documentation for the various classes and methods.

The key component is class M2MP, which encapsulates an instance of the M2MP Layer and provides methods for working with M2MP. Also important are the Channel abstract class and the classes that extend it.

2.1. Initialization

To use the M2MP Layer, create an instance of class M2MP by calling the M2MP() constructor. The constructor gets the parameters it needs to configure the M2MP Layer from the M2MP properties file (see "Configuring the M2MP Layer").

2.2. Sending M2MP Messages

To send an outgoing M2MP message, call the createOutgoingMessage() method to create an output stream for the message; write the message contents to the output stream; and close the output stream. You may write multiple outgoing messages concurrently in separate threads.

Warning: It is very important to close the output stream when finished with it, including when an exception is thrown while writing the output stream. If you don't close the output stream, the M2MP Layer will time out and abort the message.

Warning: The sending M2MP Layer will broadcast a packet containing the message data whenever enough bytes have been written to the output stream. On the receiving side, after receiving a packet of a message, the M2MP Layer starts a timeout for receiving the next packet of the message. If you pause too long while writing the message's output stream, you risk having the receiving M2MP Layer time out and abort the message.

2.3. Receiving M2MP Messages

To receive incoming M2MP messages, first register one or more appropriate message filters by calling the addMessageFilter(byte[]) method. If you don't register any message filters, the M2MP Layer will never receive any messages. Then call the acceptIncomingMessage() method to obtain an input stream for reading an incoming message that matched one of the registered message filters; read the message contents from the input stream; and close the input stream. Repeat these steps to receive the next incoming M2MP message. You may read and process multiple incoming messages concurrently by calling acceptIncomingMessage() in one thread and reading each message's input stream in its own separate thread.

Warning: Don't let the application go for a long time without calling the acceptIncomingMessage() method. If an incoming message becomes available but acceptIncomingMessage() is not called, the M2MP Layer will time out and discard the incoming message, and the application will miss the message.

A message filter is specified by a message prefix, a sequence of bytes. An incoming message matches a message filter if the initial bytes of the message are the same as the message filter's message prefix. A zero-length message prefix matches any incoming message.

To remove a message filter, call the removeMessageFilter(byte[]) method. Thereafter, the M2MP Layer will no longer receive incoming M2MP messages that match the message filter, unless they match another still-registered message filter.

The M2MP Layer receives any M2MP message sent anywhere in the system, regardless of its source, provided the M2MP message matches one of the registered message filters. A different device may have sent the M2MP message, or a different process on the same device may have sent the M2MP message. There is one exception: An outgoing message created by a certain M2MP instance will not be received by that same M2MP instance. In other words, an instance of the M2MP Layer broadcasts outgoing messages everywhere, except to itself.

2.4. Writing an M2MP Channel

An M2MP channel interfaces the M2MP Layer to the underlying network. While the M2MP Library comes with several channel implementations, you may wish to write your own custom channel implementations. Every M2MP channel implementation must extend class Channel. See class Channel for information about writing a channel implementation. Also, study the channel implementations included in the M2MP Library: class DaemonChannel, class UDPChannel, class UDPMulticastChannel, and class UDPUnicastChannel.


5. M2MP Packet Format and Processing

Using M2MP, a group of devices transmit a series of M2MP packets to each other over a shared broadcast channel. The packets convey information for two logically independent sublayers: the flow control sublayer and the message transfer sublayer. The flow control sublayer tries to ensure that a transmitting device does not send messages faster than the receiving devices can handle. The message transfer sublayer transfers the actual M2MP message data between the devices.

Packet Format

The maximum size of an M2MP packet is 508 bytes. This number is chosen so that an M2MP packet will not be fragmented if carried over an IP network layer.

The format of an M2MP packet is as follows. Multibyte fields are stored in big-endian order (most significant byte first). Bits within a 32-bit field are numbered from 31 (most significant bit) to 0 (least significant bit).

Length
(bytes)
Bits Contents
4 31 .. 0 Message ID
4 31 Last packet flag
30 .. 0 Fragment number
0 .. 500   Message fragment

The fields' contents are as follows:

An M2MP message is divided into message fragments as follows. Let the message length in bytes n = q * 500 + r, where q >= 0 and 0 <= r < 500. Then there are q message fragments of length 500 bytes, followed by one message fragment of length r bytes if r > 0.

Flow Control Sublayer

When two devices communicate over a network, flow control prevents the transmitter from sending data faster than the receiver can handle it, causing the receiver's transport layer buffers to overflow and packets to be lost. Flow control is usually done using acknowledgments: After sending a certain amount of data, the transmitter stops until it receives an acknowledgment from the receiver that the data has been processed, then the transmitter resumes sending data. While acknowledgments are easy to implement in a point-to-point connection with only one receiver, acknowledgments are more difficult to implement when there are multiple receivers, as in the applications M2MP targets. The difficulties are compounded in an ad hoc network where devices arrive and depart constantly. To keep M2MP simple, hence better suited for small mobile devices, the M2MP Layer does not use acknowledgments for flow control.

When the transmitting device's M2MP Layer sends a packet onto the external network, the M2MP Layer also receives that packet. In other words, outgoing packets are "looped back" and received from the external network along with incoming packets from other devices. All the looped-back and incoming packets go into a queue and are processed in sequence. After sending an outgoing packet, the M2MP Layer waits to send the next outgoing packet until (a) the looped-back copy of the outgoing packet has been received and removed from the queue (the looped-back packet is discarded and not passed up to higher layers), and (b) any other incoming packets after the looped-back packet have also been removed from the queue (these packets are passed up to higher layers). The M2MP Layer then sends the next outgoing packet, and the process repeats. While waiting for the looped-back packet to show up, the M2MP Layer does a timeout for the interval given by the edu.rit.m2mp.flowtimeout property in the M2MP properties file. If the timeout expires before the looped-back packet shows up, the M2MP Layer assumes the looped-back packet got lost and proceeds to send the next outgoing packet.

The idea behind this flow control scheme is that by making the transmitting device receive and process its own outgoing packets, the transmitting device is performing flow control on itself. If the transmitting device can keep up with itself, it assumes that the other receiving devices can keep up with the transmitting device. While this flow control scheme is simple, this scheme does not guarantee that some device's transport layer buffer won't overflow, as an acknowledgment-based scheme does. However, if M2MP messages are not being sent continuously (a situation for which M2MP was not designed), this flow control scheme only occasionally loses a packet due to buffer overflow.

The flow control sublayer does not address the issue of contention for the broadcast medium; it assumes that contention is resolved at the data link layer. The wired Ethernet data link layer, for example, does do contention resolution. The wireless Ethernet data link layer, on the other hand, does contention resolution for unicast packets but not for multicast or broadcast packets.

Also, the flow control sublayer does not provide reliable packet delivery. This is not a problem on a wired Ethernet which very rarely loses packets. A wireless Ethernet, on the other hand, occasionally loses packets, resulting in M2MP message failures. The application using M2MP must compensate for failed M2MP messages if necessary.

Message Transfer Sublayer

The message transfer sublayer sits on top of the flow control sublayer. The flow control sublayer accepts outgoing message fragments from the message transfer sublayer and provides incoming message fragments to the message transfer sublayer.

On the outgoing side, the message transfer sublayer breaks each outgoing M2MP message into message fragments and sends them one at a time to the flow control sublayer. The flow control sublayer blocks until the packet has been transmitted and looped back as described above, then the flow control sublayer accepts the next outgoing message fragment.

On the incoming side, whenever an incoming packet (not a looped-back packet) is received, the flow control sublayer passes the packet up to the message transfer sublayer. The message transfer sublayer uses the packet's message ID, fragment number, and last packet flag fields to reassemble the message fragments back into messages. The first fragment of each message is compared to all the registered message filters. Messages matching a message filter are passed on up to higher layers; messages not matching a message filter are discarded.

Once the message transfer sublayer receives a particular message fragment of a message, the message transfer sublayer starts a timeout while waiting for the next message fragment of the message. The timeout interval is given by the edu.rit.m2mp.messagetimeout property in the M2MP properties file. If the timeout occurs before the next message fragment arrives, the message transfer sublayer abandons the message and signals an exception to the application receiving the message.

While M2MP is not a reliable data transfer protocol, M2MP does include a feature intended to compensate for packets lost at the data link layer. (A wireless Ethernet, for example, loses packets more frequently than we'd like.) The message transfer sublayer sends each outgoing packet N times, where N is given by the edu.rit.m2mp.redundancy property in the M2MP properties file. If edu.rit.m2mp.redundancy = 2, for example, each outgoing packet is sent twice. That way, if one copy of a packet is lost, the devices may still receive the other copy, and the M2MP message will not be aborted. (If both copies of a packet are received, the message transfer sublayer discards the redundant copy.) This can greatly reduce the incidence of aborted M2MP messages when using a less-than-reliable data link layer. If the data link layer is reliable -- such as a wired Ethernet which almost never loses packets -- then set the edu.rit.m2mp.redundancy property to 1.