16  Datagram

org.arl.unet.Services.DATAGRAM

16.1 Overview

The DATAGRAM service is the fundamental data delivery service in UnetStack. A datagram is a parcel of data that is delivered atomically — either the whole datagram is delivered, or it is not delivered at all, but it is never partially delivered. Each datagram is tagged with a from address, a to address and a protocol number.

NoteMessages, datagrams and frames

Three easily-confused terms. Messages are how agents talk to each other within a node — they are never transmitted between nodes. Datagrams are the logical parcels of data exchanged between nodes. Frames are the physical layer’s datagrams — the unit a modem actually transmits and receives; larger datagrams are carried as several frames. So a DatagramReq is a message (asking an agent to send a datagram), and an RxFrameNtf is a message too (reporting that a frame — a physical-layer datagram — arrived).

The DATAGRAM service is provided by many agents across the stack, each delivering datagrams over a different scope. A physical agent (Chapter 17) delivers single-frame datagrams to immediate neighbors; a link agent (Chapter 18) delivers larger datagrams to neighbors through fragmentation and reassembly (Section 33.6); a routing agent (Chapter 21) delivers datagrams across multiple hops; and a transport agent (Chapter 23) provides reliable end-to-end delivery. Because all of these agents share the same service contract, an application can send data using a DatagramReq without needing to know which agent will carry it.

Datagrams carry several quality-of-service attributes (reliability, robustness, priority, time-to-live, etc.). These attributes, and the differences between transmission, delivery and failure, are explored in detail in Chapter 8.

16.2 Capabilities

Not every agent providing the DATAGRAM service supports every quality-of-service attribute. An agent advertises the optional features it supports through the following capabilities (org.arl.unet.DatagramCapability):

  • RELIABILITY – acknowledged delivery, requested via the reliability flag
  • FRAGMENTATION – splitting large datagrams into smaller fragments (the MTU then exceeds a single frame)
  • PRIORITY – priority-ordered delivery
  • TTL – time-to-live based expiry of stale datagrams
  • CANCELLATION – cancellation of queued datagrams (CancelReq/ClearReq)
  • PROGRESS – progress notifications (ProgressNtf) for large transfers
  • COMPRESSION – payload compression
  • FAIRNESS – fair sharing of bandwidth across flows

An agent’s capabilities can be queried using a CapabilityReq: naming a specific capability yields a CONFIRM or DISCONFIRM response, while an empty request yields the full list of capabilities. Requesting an unsupported attribute in a DatagramReq does not cause an error unless it affects correctness (e.g. reliability requested from a provider without RELIABILITY is refused); attributes that are merely advisory are ignored. Reliability is also incompatible with broadcast — a reliable DatagramReq to the broadcast address is refused, since there is no single recipient to acknowledge it.

16.3 Messages

Agents providing this service honor the following request:

  • DatagramReq – send datagram

    Field Type Default Remarks
    data byte[]
    from int 0 internal use only
    priority Priority NORMAL URGENT/HIGH/NORMAL/LOW/IDLE
    progress boolean false
    protocol int 0
    reliability boolean
    robustness Robustness NORMAL NORMAL/ROBUST
    route string
    shortcircuit boolean true
    to int 0
    ttl float NaN time-to-live in seconds

A DatagramReq is answered with an AGREE response once the datagram is accepted for delivery, a REFUSE if the request cannot be honored (e.g. the payload exceeds the provider’s MTU), or a FAILURE if something goes wrong in processing it. An AGREE only means the datagram was accepted — the eventual outcome is reported separately, through one of the following notifications sent to the requester:

If reliability was requested, the provider must eventually report either a DatagramDeliveryNtf (the recipient acknowledged the datagram) or a DatagramFailureNtf (delivery could not be confirmed). For unreliable datagrams, a provider must report a DatagramTransmissionNtf once the datagram has been transmitted; no delivery guarantee is implied. These notification messages are sent to the original requester of the datagram.

On the receiving node, the provider delivers an incoming datagram as a notification:

  • DatagramNtf – received datagram

    Field Type Default Remarks
    data byte[]
    from int 0
    priority enum NORMAL
    protocol int 0
    to int 0
    ttl float NaN

Where the notification is published matters, and all providers follow the same convention:

  • A datagram addressed to this node (or broadcast) is published on the global Topics.DATAGRAM topic. An application or agent that wants to receive datagrams subscribes to this one topic (subscribe topic(Topics.DATAGRAM)), regardless of which agent delivers them. Shells and API gateways subscribe to it automatically.
  • A datagram overheard for another node (where the provider supports snooping, e.g. the physical layer) is published on the provider agent’s own topic instead, so that overheard traffic can be observed by subscribing to that agent.

A provider may deliver a subtype of DatagramNtf carrying additional information — for example, the physical layer delivers single-frame datagrams as RxFrameNtf (Chapter 17), which adds reception timestamps and signal quality. Subscribers should therefore match on DatagramNtf to catch all incoming datagrams.

NoteShort-circuit delivery

An underwater network cannot afford unnecessary headers. When an agent can add no value to a datagram beyond passing it along — say, a small unreliable datagram handed to uwlink that fits in a single frame — it short-circuits the datagram: instead of wrapping it in its own header, it hands it down (ultimately to phy) unchanged. All the datagram providers in the default stack do this, saving precious bytes on the acoustic channel. The receiving application is none the wiser, since the datagram still arrives on Topics.DATAGRAM as usual — just as an RxFrameNtf straight from the physical layer. One place this matters is route tracing, which depends on per-hop headers and therefore never short-circuits (Section 21.7).

Providers supporting the corresponding capabilities (see below) also honor:

  • CancelReq – cancel a pending datagram transfer

    Field Type Default Remarks
    id string
  • ClearReq – clear all queued datagrams

While CancelReq cancels a specific transfer (identified by its message ID), ClearReq is a generic, field-less “drop everything” request: the receiving agent clears its queues and buffers, abandoning all pending datagrams and transfers.

Note

ClearReq is honored more widely than the CANCELLATION capability suggests — not just by link and transport agents (e.g. ECLink, CaddyLite), but also by physical and baseband agents, where it additionally aborts any ongoing or queued transmission. The pclr shell command is a convenient shorthand that sends a ClearReq to phy (Chapter 17).

Providers may also generate:

  • ProgressNtf – progress report for an ongoing large transfer

    Field Type Default Remarks
    filename string
    incoming boolean false
    peer int 0
    total long 0
    transferred long 0

16.4 Protocol numbers

The protocol number tags a datagram with the “flavor” of data it carries, so that received datagrams can be dispatched to the right consumer. Protocol 0 (Protocol.DATA) is the default for application data, and protocols 1–31 are reserved for use by stack services and agents. Applications and user agents are free to use protocol numbers from Protocol.USER (32) to Protocol.MAX (63) to identify their own traffic.

16.5 Parameters

Agents providing this service expose two parameters (org.arl.unet.DatagramParam):

  • MTU – maximum transmission unit, i.e. the largest datagram payload (in bytes) the provider can deliver
  • RTU – recommended transmission unit, i.e. the largest payload (in bytes) the provider can deliver efficiently

Datagrams up to RTU bytes are carried efficiently by the provider; datagrams between RTU and MTU bytes are still delivered, but may incur significant overheads (e.g. heavy fragmentation and retransmission). Applications transferring bulk data should prefer chunking it at the RTU.

16.6 Examples

We illustrate the basic send/receive flow using the shell. Start the 2-node-network and connect to node A’s shell. Sending a datagram is a matter of sending a DatagramReq to any DATAGRAM provider — here the physical agent phy. The provider answers with an AGREE to confirm the datagram was accepted, and later notifies the sender that the frame was transmitted with a TxFrameNtf (a DatagramTransmissionNtf subtype). Since these notifications are sent to the requester, they show up in the shell without subscribing to phy:

> phy << new DatagramReq(to: 31, data: [1, 2, 3, 4])
AGREE
phy >> TxFrameNtf:INFORM[type:DATA to:0 txStartTime:3505249045]

On node B, the datagram arrives as an RxFrameNtf — the DatagramNtf subtype generated by the physical layer, carrying the reception timestamp and signal quality. Because it is addressed to this node, it is published on the Topics.DATAGRAM topic, which the shell subscribes to automatically, so it too appears without any explicit subscription:

phy >> RxFrameNtf:INFORM[type:DATA from:232 to:31 rxStartTime:1131470074 rssi:-72.6 (4 bytes)]
  01020304

Had we sent the datagram through a link agent (uwlink) or the router instead, the same DatagramReq would have been honored, with the receiving side seeing a DatagramNtf from the corresponding agent.

16.7 Implementations

The DATAGRAM service is not provided by a single dedicated agent; rather, it is offered by many agents across the stack, each delivering datagrams over a different scope. Because the DATAGRAM service is always paired with a more specific service, each of these agents is documented in the chapter for that more specific service:

  • The physical layer (modem) delivers single-frame datagrams to immediate neighbors — see Chapter 17.
  • Link agents deliver datagrams to immediate neighbors, using fragmentation and reassembly for datagrams larger than a single frame — see Chapter 18.
  • The router delivers datagrams across multiple hops to nodes that are not directly reachable — see Chapter 21.
  • The transport/remote agent provides reliable, end-to-end delivery of arbitrarily large datagrams — see Chapter 24.

Their DATAGRAM-related parameters and behavior are described in those chapters, and are not duplicated here.