Silk

silk/tls_connection

Profiles: aarch64-apple-darwin, aarch64-unknown-linux-gnu, aarch64-unknown-linux-gnu-no-libc, wasm32-unknown-unknown, x86_64-unknown-linux-gnu, x86_64-unknown-linux-gnu-no-libc.

Authenticated TLS 1.3 with one owned partial-byte transport.

When to use

Use authenticateOwned when a caller must retain, move, pool, or explicitly close one authenticated provider owner. Use withClient when the owner belongs to one lexical scope. Prepare the trust snapshot independently before transferring the provider to either operation.

Details

Authentication consumes one provider and one already-prepared trust snapshot, samples wall time once, constructs the TLS client, and drives its handshake through exact partial transfers. The earlier of the finite handshake-duration deadline and an optional external absolute deadline bounds all handshake transport work. Ownership is published only after authentication and a final deadline check.

Gotchas

Direct owned I/O is guarded: typed failure or structured cancellation closes the owner and its provider before an ambiguous buffer can be offered again. OwnedConnection.shutdownWrite performs TLS grace for the write direction; OwnedConnection.close immediately invalidates and terminally closes the provider. Scoped close failures are suppressed so they cannot replace the protected result. Fatal traps remain outside structured finalization guarantees.

Examples

Supply every connection dependency explicitly

This deterministic wiring example uses an empty transport and trust snapshot, so authentication fails and main returns 1. A real application supplies authenticated peer bytes and selected trust through the same lexical boundaries.

import silk.allocator { Allocator, OutOfMemoryError }
import silk.effect { Effect }
import silk.https_identity { HttpsIdentity, OriginHost, ReferenceIdentity }
import silk.memory_byte_duplex { MemoryByteDuplex, MemoryReadEvent, MemoryWriteEvent }
import silk.monotonic_clock { MonotonicClock }
import silk.option { Option }
import silk.random { Random }
import silk.result { Result }
import silk.system_clock { Instant, SystemClock }
import silk.tls_client { AlpnConfig, ClientConfig, ClientLimits }
import silk.tls_connection { OwnedConnection, ConnectionOptions, withClient }
import silk.trust_anchor { TrustAnchor }
import silk.trust_snapshot { SnapshotLimits, TrustSnapshot }
import silk.u64
import silk.usize
import silk.vector { Vector }

struct FixedWall {}
impl SystemClock for FixedWall {
  effect fn now(self: &mut Self) -> Instant { return SystemClock.make(0, 0) }
  effect fn getResolution(self: &mut Self) -> u64 { return u64.toU64(1) }
}

struct FixedMonotonic {}
impl MonotonicClock for FixedMonotonic {
  effect fn now(self: &mut Self) -> Instant { return SystemClock.make(0, 0) }
  effect fn getResolution(self: &mut Self) -> u64 { return u64.toU64(1) }
  effect fn waitUntil(self: &mut Self, when: Instant) -> () { drop when return () }
  effect fn waitFor(self: &mut Self, howLong: u64) -> () { drop howLong return () }
}

struct ExampleRandom {}
impl Random for ExampleRandom {
  effect fn fillBytes(self: &mut Self, output: &mut [u8]) -> () {
    let mut index = usize.ZERO
    while index < output.length { output[index] = 1 index = index + usize.ONE }
    return ()
  }
}

fn reference<'a>(host: &'a [u8]) -> ReferenceIdentity<'a> {
  return match move HttpsIdentity.reference(OriginHost<'a>.Dns {bytes: host}) {
    Result.Success {value} => value
    Result.Failure {error} => { let invalid = 1 / 0 return reference(host) }
  }
}

fn emptyTrust() -> TrustSnapshot {
  return match move TrustSnapshot.fromAnchors(
    Vector.make<TrustAnchor>(),
    SnapshotLimits {anchors: 0, encodedBytes: 0},
  ) {
    Result.Success {value} => move value
    Result.Failure {error} => { let invalid = 1 / 0 return emptyTrust() }
  }
}

effect fn inspect(
  connection: &mut OwnedConnection<MemoryByteDuplex>,
) -> i32 {
  drop connection
  return 0
}

effect fn failed<E>(error: E) -> i32 { drop error return 1 }

effect fn program() -> i32 ! OutOfMemoryError {
  let mut allocator = Allocator.systemAllocatorProvider()
  let reads = Vector.make<MemoryReadEvent>()
  let writes = Vector.make<MemoryWriteEvent>()
  let mut transport = run MemoryByteDuplex.make(
    move reads,
    move writes,
    256,
    4,
    Option.none<i32>(),
  ) |> Effect.provideMut<Allocator>(&mut allocator)
  let trust = emptyTrust()
  let mut wall = FixedWall {}
  let mut monotonic = FixedMonotonic {}
  let mut random = ExampleRandom {}
  let host = b"example.com"
  let config = ClientConfig {
    reference: reference(&host),
    alpn: AlpnConfig.defaults(),
    limits: ClientLimits.defaults(),
  }
  let attempt = withClient<i32, never>(
    move transport,
    &config,
    move trust,
    ConnectionOptions.defaults(),
    inspect,
  )
    |> Effect.provideMut<SystemClock>(&mut wall)
    |> Effect.provideMut<MonotonicClock>(&mut monotonic)
    |> Effect.provideMut<Random>(&mut random)
    |> Effect.provideMut<Allocator>(&mut allocator)
  return run Effect.catchAll(move attempt, failed)
}

pub fn main() -> i32 { return run Effect.catchAll(program(), failed) }

Import as OwnedConnection with import silk.tls_connection { OwnedConnection }.

Public declarations: 6.

ConnectionPhase

pub enum ConnectionPhase

The visible lifecycle of one authenticated connection.

Open

Open = 0

Both authenticated directions remain available.

PeerEnded

PeerEnded = 1

The peer sent authenticated close_notify; buffered plaintext may remain.

WriteShutdown

WriteShutdown = 2

Local close_notify and transport write shutdown completed.

Invalid

Invalid = 3

A protocol or transport failure made the lease unusable.

Closed

Closed = 4

Terminal close consumed provider authority; later I/O cannot reach the provider.

ConnectionError

pub union ConnectionError

A scoped connection failure that preserves its originating boundary.

Tls

ConnectionError.Tls { error: TlsError }: ConnectionError

The TLS state machine rejected peer input or caller state.

Field error

pub error: TlsError

The complete sticky TLS failure.

Io

ConnectionError.Io { error: ByteIoError }: ConnectionError

The byte provider rejected a non-handshake operation.

Field error

pub error: ByteIoError

The complete byte-I/O failure.

HandshakeTimeout

ConnectionError.HandshakeTimeout: ConnectionError

The single absolute handshake deadline was reached.

ConnectionOptions

pub struct ConnectionOptions

Bounded policy copied for one owned client authentication.

Field handshakeTimeoutNanoseconds

pub handshakeTimeoutNanoseconds: u64

Complete handshake duration on the active monotonic timeline.

Field externalDeadline

pub externalDeadline: silk/option.Option<silk/system_clock.Instant>

Optional caller-owned absolute deadline clamped against the handshake duration.

Associated function ConnectionOptions.defaults

pub fn defaults() -> ConnectionOptions

Returns the 30-second handshake timeout without an external deadline.

OwnedConnection

pub struct OwnedConnection<P>

One affine authenticated TLS client owning its exact byte provider.

Method OwnedConnection.phase

pub fn phase<P, 'life1>(self: &'life1 OwnedConnection<P>) -> ConnectionPhase

Returns the current directional, invalid, or terminal phase.

Method OwnedConnection.authentication

pub fn authentication<P, 'a>(self: &'a OwnedConnection<P>) -> silk/option.Option<silk/tls_client.Authentication<'a>>

Borrows the authenticated session evidence retained by this connection.

Method OwnedConnection.readSome

pub effect<'env> fn readSome<P: 'env, 'connection: 'env, 'life2: 'env, 'env>(self: &'connection mut OwnedConnection<P>, output: &'life2 mut [u8], deadline: silk/option.Option<silk/system_clock.Instant>) -> ReadTransfer ! ConnectionError | OutOfMemoryError ? &mut MonotonicClock | &mut Allocator | &mut Random where &mut P provides &ByteDuplex from &mut ByteDuplex, &mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random

Reads one verified plaintext prefix or clean authenticated peer end.

Details

Mandatory TLS output is sent first. Underlying end without close_notify is truncation.

Method OwnedConnection.writeSome

pub effect<'env> fn writeSome<P: 'env, 'connection: 'env, 'life2: 'env, 'env>(self: &'connection mut OwnedConnection<P>, input: &'life2 [u8], deadline: silk/option.Option<silk/system_clock.Instant>) -> usize ! ConnectionError | OutOfMemoryError ? &mut MonotonicClock | &mut Allocator | &mut Random where &mut P provides &ByteDuplex from &mut ByteDuplex, &mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random

Encrypts and transmits one positive application prefix.

Method OwnedConnection.flush

pub effect<'env> fn flush<P: 'env, 'connection: 'env, 'env>(self: &'connection mut OwnedConnection<P>, deadline: silk/option.Option<silk/system_clock.Instant>) -> () ! ConnectionError | OutOfMemoryError ? &mut MonotonicClock | &mut Allocator | &mut Random where &mut P provides &ByteDuplex from &mut ByteDuplex, &mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random

Drains mandatory TLS output and flushes the underlying byte boundary.

Method OwnedConnection.shutdownWrite

pub effect<'env> fn shutdownWrite<P: 'env, 'connection: 'env, 'env>(self: &'connection mut OwnedConnection<P>, deadline: silk/option.Option<silk/system_clock.Instant>) -> () ! ConnectionError | OutOfMemoryError ? &mut MonotonicClock | &mut Allocator | &mut Random where &mut P provides &ByteDuplex from &mut ByteDuplex, &mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random

Sends and flushes TLS close_notify, then closes only the transport write direction.

Method OwnedConnection.close

pub effect<'env> fn close<P: 'env, 'life1: 'env, 'env>(self: &'life1 mut OwnedConnection<P>) -> () ! ConnectionError ? Without<&mut ByteDuplex, &ByteDuplex> where &mut P provides &ByteDuplex from &mut ByteDuplex

Terminally closes the exact provider without TLS grace or retry.

Details

The connection becomes Closed before provider dispatch. Repeated close is local and successful; a first provider close failure remains observable while later I/O stays closed.

authenticateOwned

pub effect<'env> fn authenticateOwned<P: 'env, 'life1: 'env, 'life2: 'env, 'env>(provider: P, config: &'life1 silk/tls_client.ClientConfig<'life2>, trust: TrustSnapshot, options: ConnectionOptions) -> silk/tls_connection.OwnedConnection<P> ! ConnectionError | OutOfMemoryError ? &mut SystemClock | &mut MonotonicClock | &mut Allocator | &mut Random where &mut P provides &ByteDuplex from &mut ByteDuplex, &mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random

Consumes a provider and prepared trust snapshot and returns one authenticated affine owner.

Details

The provider enters a nonparking guard before time sampling, client construction, allocation, or transport work. Authentication publishes only after the final deadline check; typed failure and structured cancellation close an unpublished provider exactly once.

withClient

pub effect<'env1> fn withClient<'env: 'env1, A, E, ?CallbackRequirements, P: 'env1, 'life5: 'env1, 'life6: 'env1, 'env1>(provider: P, config: &'life5 silk/tls_client.ClientConfig<'life6>, trust: TrustSnapshot, options: ConnectionOptions, callback: for<'call> once fn<'env>(&'call mut silk/tls_connection.OwnedConnection<P>) -> once Effect<'call & 'env; A ! E ? CallbackRequirements>) -> A ! E | ConnectionError | OutOfMemoryError ? CallbackRequirements | &mut SystemClock | &mut MonotonicClock | &mut Allocator | &mut Random where &mut P provides &ByteDuplex from &mut ByteDuplex, &mut P provides &ByteDuplex from &mut ByteDuplex | &mut MonotonicClock | &mut Allocator | &mut Random, CallbackRequirements in Without<CallbackRequirements, &ByteDuplex>

Authenticates, lends, and terminally closes the same authoritative owned connection.

On this page