npm package: @hla4ts/transport
Description: HLA 4 Federate Protocol transport layer with TLS and message framing
Latest version: 0.1.1

# @hla4ts/transport

**HLA 4 Federate Protocol Transport Layer**

This package provides the transport layer for the HLA 4 Federate Protocol, handling TCP/TLS connections, message framing, and low-level communication with HLA 4 RTIs.

## Overview

The Federate Protocol uses a binary framing format over TCP or TLS connections. Each message has a 24-byte header followed by an optional payload. This package handles:

- **Connection management** - TCP and TLS socket connections
- **Message framing** - Encoding/decoding the 24-byte header
- **Stream handling** - Buffering partial messages, extracting multiple messages from a single chunk

## Installation

```bash
bun add @hla4ts/transport
```

## Quick Start

```typescript
import { 
  TlsTransport, 
  MessageType, 
  encodeMessage,
  FEDERATE_PROTOCOL_VERSION,
} from '@hla4ts/transport';

// Create a TLS transport
const transport = new TlsTransport({
  host: 'rti.example.com',
  port: 15165,
});

// Set up event handlers
transport.setEventHandlers({
  onMessage: (msg) => {
    console.log('Received:', MessageType[msg.header.messageType]);
    console.log('Payload size:', msg.payload.length);
  },
  onClose: (hadError) => {
    console.log('Connection closed', hadError ? '(with error)' : '');
  },
  onError: (err) => {
    console.error('Transport error:', err);
  },
});

// Connect
await transport.connect();

// Send a CTRL_NEW_SESSION message
const payload = new Uint8Array(4);
new DataView(payload.buffer).setUint32(0, FEDERATE_PROTOCOL_VERSION, false);

const message = encodeMessage(
  1,                            // sequence number
  0n,                           // session ID (0 for new session)
  0,                            // last received sequence number
  MessageType.CTRL_NEW_SESSION, // message type
  payload                       // payload
);

await transport.send(message);

// Later: disconnect
await transport.disconnect();
```

## Sequence Diagram

```mermaid
sequenceDiagram
  participant RTI
  participant Transport as Tcp/TlsTransport
  participant Decoder as FrameDecoder
  participant App as Federate Code
  RTI-->>Transport: TCP/TLS bytes
  Transport-->>Decoder: push(chunk)
  Decoder-->>App: onMessage(header, payload)
  App->>Transport: send(encoded message)
  Transport-->>RTI: TCP/TLS bytes
```

## Message Format

Every Federate Protocol message has a **24-byte header**:

```
┌─────────────────────────────────────────────────────────────────┐
│ Offset │ Size  │ Field                    │ Description         │
├────────┼───────┼──────────────────────────┼─────────────────────┤
│ 0      │ 4     │ packetSize               │ Total message size  │
│ 4      │ 4     │ sequenceNumber           │ Message sequence #  │
│ 8      │ 8     │ sessionId                │ Session identifier  │
│ 16     │ 4     │ lastReceivedSequenceNum  │ ACK for flow ctrl   │
│ 20     │ 4     │ messageType              │ Type of message     │
├────────┴───────┴──────────────────────────┴─────────────────────┤
│ 24     │ var   │ payload                  │ Message payload     │
└─────────────────────────────────────────────────────────────────┘
```

All integers are **big-endian** (network byte order).

## Message Types

### Control Messages (Session Management)

| Code | Name | Direction | Description |
|------|------|-----------|-------------|
| 1 | `CTRL_NEW_SESSION` | C → S | Request new session |
| 2 | `CTRL_NEW_SESSION_STATUS` | S → C | Session creation result |
| 3 | `CTRL_HEARTBEAT` | Both | Keep-alive ping |
| 4 | `CTRL_HEARTBEAT_RESPONSE` | Both | Keep-alive pong |
| 5 | `CTRL_TERMINATE_SESSION` | C → S | Request session end |
| 6 | `CTRL_SESSION_TERMINATED` | S → C | Session ended |
| 10 | `CTRL_RESUME_REQUEST` | C → S | Resume dropped session |
| 11 | `CTRL_RESUME_STATUS` | S → C | Resume result |

### HLA Messages

| Code | Name | Direction | Description |
|------|------|-----------|-------------|
| 20 | `HLA_CALL_REQUEST` | C → S | RTI service call (protobuf `CallRequest`) |
| 21 | `HLA_CALL_RESPONSE` | S → C | RTI response (protobuf `CallResponse`) |
| 22 | `HLA_CALLBACK_REQUEST` | S → C | Federate callback (protobuf `CallbackRequest`) |
| 23 | `HLA_CALLBACK_RESPONSE` | C → S | Callback ACK (protobuf `CallbackResponse`) |

## API Reference

### Transports

#### `TlsTransport`

Secure TLS connection (recommended for production):

```typescript
import { TlsTransport, Ports } from '@hla4ts/transport';

const transport = new TlsTransport({
  host: 'rti.example.com',
  port: Ports.TLS,              // 15165 (default)
  connectionTimeout: 10000,     // 10 seconds (default)
  noDelay: true,                // TCP_NODELAY (default)
  
  // TLS options
  rejectUnauthorized: true,     // Verify server cert (default)
  ca: '/path/to/ca.pem',        // Custom CA (optional)
  cert: '/path/to/client.pem',  // Client cert for mTLS (optional)
  key: '/path/to/client-key.pem', // Client key for mTLS (optional)
  serverName: 'rti.example.com',  // SNI hostname (optional)
});
```

#### `TcpTransport`

Plain TCP connection (for development/testing only):

```typescript
import { TcpTransport, Ports } from '@hla4ts/transport';

const transport = new TcpTransport({
  host: 'localhost',
  port: Ports.TCP,  // 15164 (default)
});
```

### Transport Interface

Both transports implement the `Transport` interface:

```typescript
interface Transport {
  connect(): Promise<void>;
  disconnect(): Promise<void>;
  isConnected(): boolean;
  send(data: Uint8Array): Promise<void>;
  setEventHandlers(handlers: TransportEvents): void;
  getProtocolName(): string;
  getRemoteAddress(): string | null;
}

interface TransportEvents {
  onMessage?: (message: ReceivedMessage) => void;
  onClose?: (hadError: boolean) => void;
  onError?: (error: Error) => void;
}

interface ReceivedMessage {
  header: MessageHeader;
  payload: Uint8Array;
}
```

### Message Header Functions

```typescript
import {
  encodeHeader,
  decodeHeader,
  encodeMessage,
  getPayloadSize,
  HEADER_SIZE,        // 24
  NO_SESSION_ID,      // 0n
  NO_SEQUENCE_NUMBER, // 0
} from '@hla4ts/transport';

// Encode just the header (24 bytes)
const header = encodeHeader(
  payloadSize,              // payload size in bytes
  sequenceNumber,           // sequence number
  sessionId,                // session ID (bigint)
  lastReceivedSequenceNum,  // ACK
  messageType               // MessageType enum
);

// Encode header + payload
const message = encodeMessage(
  sequenceNumber,
  sessionId,
  lastReceivedSequenceNum,
  messageType,
  payload  // optional Uint8Array
);

// Decode a header
const header = decodeHeader(buffer);  // throws on invalid data
console.log(header.packetSize);
console.log(header.sequenceNumber);
console.log(header.sessionId);
console.log(header.messageType);

// Get payload size from header
const payloadSize = getPayloadSize(header);
```

### Frame Decoder

For advanced use cases, you can use the `FrameDecoder` directly:

```typescript
import { FrameDecoder } from '@hla4ts/transport';

const decoder = new FrameDecoder();

decoder.onMessage = (msg) => {
  console.log('Complete message received');
  console.log('Type:', msg.header.messageType);
  console.log('Payload:', msg.payload);
};

decoder.onError = (err) => {
  console.error('Decode error:', err);
};

// Feed data as it arrives (handles fragmentation automatically)
socket.on('data', (chunk) => {
  decoder.push(new Uint8Array(chunk));
});

// Check buffered data
console.log('Bytes waiting:', decoder.bufferedBytes);

// Reset after connection reset
decoder.reset();
```

### Constants

```typescript
import {
  FEDERATE_PROTOCOL_VERSION,  // 1
  Ports,
  Protocol,
  NewSessionStatus,
  ResumeStatus,
} from '@hla4ts/transport';

// Default ports
Ports.TCP   // 15164
Ports.TLS   // 15165
Ports.WS    // 80
Ports.WSS   // 443

// Protocol names
Protocol.TCP  // "tcp"
Protocol.TLS  // "tls"
Protocol.WS   // "websocket"
Protocol.WSS  // "websocketsecure"

// Session status codes
NewSessionStatus.SUCCESS                      // 0
NewSessionStatus.UNSUPPORTED_PROTOCOL_VERSION // 1
NewSessionStatus.OUT_OF_RESOURCES             // 2
NewSessionStatus.BAD_MESSAGE                  // 3
NewSessionStatus.OTHER_ERROR                  // 99

// Resume status codes
ResumeStatus.SUCCESS           // 0
ResumeStatus.SESSION_NOT_FOUND // 1
ResumeStatus.NOT_ALLOWED       // 2
```

## Session Protocol Flow

```
┌─────────────┐                              ┌─────────────┐
│   Federate  │                              │     RTI     │
└──────┬──────┘                              └──────┬──────┘
       │                                            │
       │──── TCP/TLS Connect ──────────────────────>│
       │                                            │
       │──── CTRL_NEW_SESSION (version=1) ─────────>│
       │                                            │
       │<─── CTRL_NEW_SESSION_STATUS (sessionId) ───│
       │                                            │
       │──── HLA_CALL_REQUEST (Connect) ───────────>│
       │<─── HLA_CALL_RESPONSE ─────────────────────│
       │                                            │
       │──── HLA_CALL_REQUEST (JoinFederation) ────>│
       │<─── HLA_CALL_RESPONSE ─────────────────────│
       │                                            │
       │     ... HLA calls and callbacks ...        │
       │                                            │
       │<─── HLA_CALLBACK_REQUEST (Discover...) ────│
       │──── HLA_CALLBACK_RESPONSE ────────────────>│
       │                                            │
       │──── CTRL_HEARTBEAT ───────────────────────>│
       │<─── CTRL_HEARTBEAT_RESPONSE ──────────────│
       │                                            │
       │──── CTRL_TERMINATE_SESSION ───────────────>│
       │<─── CTRL_SESSION_TERMINATED ──────────────│
       │                                            │
       │──── TCP/TLS Disconnect ───────────────────>│
       │                                            │
```

## Error Handling

```typescript
try {
  await transport.connect();
} catch (err) {
  if (err.message.includes('Connection timeout')) {
    console.error('RTI not reachable');
  } else if (err.message.includes('certificate')) {
    console.error('TLS certificate error');
  }
}

transport.setEventHandlers({
  onError: (err) => {
    console.error('Transport error:', err);
    // Attempt reconnection...
  },
  onClose: (hadError) => {
    if (hadError) {
      console.error('Connection lost unexpectedly');
    }
  },
});
```

## Testing

```bash
cd packages/transport
bun test
```

## Related Packages

- [`@hla4ts/proto`](../proto) - Protocol buffer types
- [`@hla4ts/session`](../session) - Session management
- [`@hla4ts/hla-api`](../hla-api) - High-level HLA API facade

## References

- [IEEE 1516-2025](https://standards.ieee.org/standard/1516-2025.html) - HLA 4 Standard
- [Pitch FedProClient](https://github.com/Pitch-Technologies/FedProClient) - Reference implementation

## License

MIT