Skip to content

MillerTechnologyPeru/transport-services

Repository files navigation

Transport Services

Swift 6.0 Platforms License macOS Linux Documentation

TransportServices is a modern, protocol-agnostic networking framework for Swift, built on the principles of the IETF Transport Services (TAPS) architecture. It provides a high-level, asynchronous, and message-oriented API that allows applications to express their networking intent rather than being hard-coded to a specific transport protocol like TCP or UDP.

Motivation: Evolving the Network API

Traditional networking APIs, like Berkeley Sockets, tightly couple applications to specific transport protocols. This legacy model presents several challenges in today's rapidly evolving internet:

  • Protocol Rigidity: Applications must be manually updated to support new protocols like QUIC or SCTP.
  • Path Agility: They cannot easily take advantage of multiple network interfaces (e.g., Wi-Fi and Cellular) simultaneously for better performance and reliability.
  • Repetitive Logic: Common patterns like "Happy Eyeballs" (racing IPv4 and IPv6) must be re-implemented in every application.

As outlined in the TAPS Architecture (spec/rfc9621.txt), the goal of this library is to solve these problems by providing an abstraction layer. The TransportServices implementation can dynamically select the best protocol and network path based on application requirements and network conditions, enabling faster, more reliable, and more resilient networking without requiring application changes.

Core Concepts

This library implements the abstract API defined in spec/rfc9622.txt, centered around these key concepts:

  • Preconnection: An object for specifying your networking requirements before a connection is established. You define what you need (reliability, ordering, low latency) rather than picking a protocol.
  • Connection: A unified, protocol-agnostic object representing a communication channel. Once established, you send() and receive() messages regardless of whether the underlying transport is TCP, QUIC, or UDP.
  • Listener: An object for accepting incoming connections, which creates new Connection objects as peers connect.
  • Asynchronous, Event-Driven API: All network operations are non-blocking and communicate their results through events, fitting naturally into modern Swift concurrency.
  • Message-Oriented Data Transfer: Data is sent and received as discrete Message objects, which aligns better with application logic than raw byte streams.
  • Protocol & Path Agility: The framework handles the complexity of choosing between protocols (e.g., TCP, UDP), racing connections (e.g., "Happy Eyeballs"), and migrating between network paths.
  • Extensible Security: Integrates transport security (like TLS) as a first-class feature.

Table of Contents

Installation

Swift Package Manager

Add the TransportServices package to your Package.swift dependencies:

// swift-tools-version:6.1
import PackageDescription

let package = Package(
    name: "YourProject",
    dependencies: [
        .package(url: "https://github.com/edgeengineer/transport-services", from: "0.0.2")
    ],
    targets: [
        .target(
            name: "YourTarget",
            dependencies: [
                .product(name: "TransportServices", package: "transport-services")
            ]
        )
    ]
)

Quick Start

1. Client Example: Connecting to a Service

This example shows how to connect to an echo service. The application requests a reliable transport but does not need to know if it's TCP or another protocol.

import TransportServices

// 1. Specify the remote endpoint
let remoteEndpoint = RemoteEndpoint(host: "echo.example.com", port: 7)

// 2. Define transport properties. We need reliability.
var properties = TransportProperties()
properties.reliability = .require

// 3. Create a Preconnection with our endpoint and properties.
//    No security is needed for this simple example.
let preconnection = Preconnection(remote: remoteEndpoint,
                                  properties: properties,
                                  security: .disabled)

// 4. Initiate the connection
let connection = try await preconnection.initiate()

Task {
    // Listen for events on the connection
    for await event in connection.events {
        switch event {
        case .ready:
            print("Connection is ready. Sending 'Hello'.")
            let message = Message("Hello, TAPS!".data(using: .utf8)!)
            try await connection.send(message)
        case .received(let message):
            let response = String(data: message.data, encoding: .utf8) ?? "Invalid UTF-8"
            print("Received response: \(response)")
            await connection.close() // We are done, close the connection
        case .closed:
            print("Connection closed.")
            return // End the task
        case .error(let error):
            print("Connection error: \(error)")
            return // End the task
        default:
            break
        }
    }
}

2. Server Example: Listening for Connections

This example shows how to create a simple server that listens for incoming connections and echoes back any messages it receives.

import TransportServices

// 1. Specify the local endpoint to listen on.
//    Listen on all interfaces on port 1234.
let localEndpoint = LocalEndpoint(port: 1234)

// 2. Define transport properties. We require reliability.
var properties = TransportProperties()
properties.reliability = .require

// 3. Create a Preconnection.
let preconnection = Preconnection(local: localEndpoint,
                                  properties: properties,
                                  security: .disabled)

// 4. Start listening for incoming connections.
let listener = try await preconnection.listen()
print("Server listening on port 1234...")

// 5. Accept new connections in a loop.
for await newConnection in listener.connections {
    print("Accepted a new connection from \(newConnection.remoteEndpoint?.host ?? "unknown")")
    
    // Handle each connection concurrently in its own Task.
    Task {
        for await event in newConnection.events {
            if case .received(let message) = event {
                let receivedText = String(data: message.data, encoding: .utf8) ?? ""
                print("Received '\(receivedText)', echoing back.")
                // Echo the message back to the client.
                try await newConnection.send(message)
            }
        }
    }
}

Documentation

Comprehensive guide covering:

  • Core concepts and architecture
  • Complete API reference
  • Advanced features (Rendezvous, Connection Groups, Multicast, 0-RTT)
  • Best practices and performance tips
  • Migration guides from BSD sockets, URLSession, and Network.framework

Practical, runnable examples demonstrating:

  • Basic client/server connections
  • Peer-to-peer with NAT traversal
  • Connection groups and multistreaming
  • Multicast communication
  • Custom security callbacks
  • 0-RTT optimization techniques

Advanced Usage

The TransportServices framework is designed to support advanced networking scenarios. The full implementation will include:

  • Peer-to-Peer (Rendezvous): Establishing direct connections between clients, potentially using STUN/ICE for NAT traversal (RFC 9622, Section 7.3).
  • Connection Groups (Clone): Managing multiple streams within a single transport session, ideal for protocols like QUIC and HTTP/2 (RFC 9622, Section 7.4).
  • Multicast: Joining multicast groups for efficient one-to-many communication (RFC 9622, Section 6.1.1).
  • Custom Security: Providing fine-grained control over TLS parameters and trust evaluation.

For a detailed roadmap of planned features, please see the IMPROVEMENTS.md file.

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

About

A Cross Platform Swift 6.1 Implementation of RFC9622

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages