Skip to content

TCPConnection[optional TCP: TCPBackend ref]

[Source]

The TCP connection: all connection state and I/O, including SSL. A TCPConnectionActor owns one and delegates to it.

Create it with one of the four constructors -- client, server, ssl_client, ssl_server -- using TCPConnection.none() as the field initializer before that. An open plaintext connection can be upgraded to TLS with start_tls. See the package documentation for the full lifecycle.

class ref TCPConnection[optional TCP: TCPBackend ref]

Constructors

client

[Source]

Create a client-side plaintext connection. An optional connection_timeout bounds the TCP Happy Eyeballs phase. If the timeout fires before _on_connected, the connection fails with ConnectionFailedTimeout.

new ref client(
  auth: TCPConnectAuth val,
  host: String val,
  port: String val,
  from: String val,
  enclosing: TCPConnectionActor[TCP] ref,
  ler: ClientLifecycleEventReceiver[TCP] ref,
  read_buffer_size: ReadBufferSize = call,
  ip_version: IPVersion = reference,
  connection_timeout: (ConnectionTimeout | None val) = reference)
: TCPConnection[TCP] ref^

Parameters

Returns


server

[Source]

Create a server-side plaintext connection from an accepted socket fd'.

new ref server(
  auth: TCPServerAuth val,
  fd': U32 val,
  enclosing: TCPConnectionActor[TCP] ref,
  ler: ServerLifecycleEventReceiver[TCP] ref,
  read_buffer_size: ReadBufferSize = call)
: TCPConnection[TCP] ref^

Parameters

Returns


ssl_client

[Source]

Create a client-side SSL connection. The SSL session is created from the provided SSLContext. If session creation fails, the connection reports failure asynchronously via _on_connection_failure(ConnectionFailedSSL). An optional connection_timeout bounds the connect-to-ready phase (TCP Happy Eyeballs + TLS handshake). If the timeout fires before _on_connected, the connection fails with ConnectionFailedTimeout.

new ref ssl_client(
  auth: TCPConnectAuth val,
  ssl_ctx: SSLContext val,
  host: String val,
  port: String val,
  from: String val,
  enclosing: TCPConnectionActor[TCP] ref,
  ler: ClientLifecycleEventReceiver[TCP] ref,
  read_buffer_size: ReadBufferSize = call,
  ip_version: IPVersion = reference,
  connection_timeout: (ConnectionTimeout | None val) = reference)
: TCPConnection[TCP] ref^

Parameters

Returns


ssl_server

[Source]

Create a server-side SSL connection. The SSL session is created from the provided SSLContext. If session creation fails, the connection reports failure asynchronously via _on_start_failure(StartFailedSSL) and closes the fd.

new ref ssl_server(
  auth: TCPServerAuth val,
  ssl_ctx: SSLContext val,
  fd': U32 val,
  enclosing: TCPConnectionActor[TCP] ref,
  ler: ServerLifecycleEventReceiver[TCP] ref,
  read_buffer_size: ReadBufferSize = call)
: TCPConnection[TCP] ref^

Parameters

Returns


none

[Source]

new ref none()
: TCPConnection[TCP] ref^

Returns


Public Functions

keepalive

[Source]

Sets the TCP keepalive timeout to approximately secs seconds. Exact timing is OS dependent. If secs is zero, TCP keepalive is disabled. TCP keepalive is disabled by default. This can only be set on a connected socket.

fun ref keepalive(
  secs: U32 val)
: None val

Parameters

  • secs: U32 val

Returns


set_nodelay

[Source]

Turn Nagle on/off. Defaults to on (Nagle enabled, nodelay off). When enabled (state = true), small writes are sent immediately without waiting to coalesce — useful for latency-sensitive protocols. When disabled (state = false), the OS may buffer small writes.

Returns 0 on success, or a non-zero errno on failure. Only meaningful on a connected socket — returns non-zero if the connection is not open.

fun box set_nodelay(
  state: Bool val)
: U32 val

Parameters

Returns


get_so_rcvbuf

[Source]

Get the OS receive buffer size for this socket.

Returns a 2-tuple: (errno, value). On success, errno is 0 and value is the buffer size in bytes. On failure, errno is non-zero and value should be ignored. Only meaningful on a connected socket — returns (1, 0) if the connection is not open.

fun box get_so_rcvbuf()
: (U32 val , U32 val)

Returns


set_so_rcvbuf

[Source]

Set the OS receive buffer size for this socket. The OS may round the requested size up to a minimum or clamp it to a maximum.

Returns 0 on success, or a non-zero errno on failure. Only meaningful on a connected socket — returns non-zero if the connection is not open.

fun box set_so_rcvbuf(
  bufsize: U32 val)
: U32 val

Parameters

  • bufsize: U32 val

Returns


get_so_sndbuf

[Source]

Get the OS send buffer size for this socket.

Returns a 2-tuple: (errno, value). On success, errno is 0 and value is the buffer size in bytes. On failure, errno is non-zero and value should be ignored. Only meaningful on a connected socket — returns (1, 0) if the connection is not open.

fun box get_so_sndbuf()
: (U32 val , U32 val)

Returns


set_so_sndbuf

[Source]

Set the OS send buffer size for this socket. The OS may round the requested size up to a minimum or clamp it to a maximum.

Returns 0 on success, or a non-zero errno on failure. Only meaningful on a connected socket — returns non-zero if the connection is not open.

fun box set_so_sndbuf(
  bufsize: U32 val)
: U32 val

Parameters

  • bufsize: U32 val

Returns


getsockopt

[Source]

General interface to getsockopt(2) for accessing any socket option.

The option_max_size argument is the maximum number of bytes the caller expects the kernel to return. This method allocates a buffer of that size before calling getsockopt(2).

Returns a 2-tuple: on success, (0, data) where data is the bytes returned by the kernel, sized to the actual length the kernel wrote. On failure, (errno, undefined) — the second element must be ignored. Only meaningful on a connected socket — returns (1, empty) if the connection is not open.

For commonly-tuned options, prefer the dedicated convenience methods (set_nodelay, get_so_rcvbuf, etc.). Do not change the socket's non-blocking mode — lori's event-driven I/O requires non-blocking sockets.

fun box getsockopt(
  level: I32 val,
  option_name: I32 val,
  option_max_size: USize val = 4)
: (U32 val , Array[U8 val] iso^)

Parameters

  • level: I32 val
  • option_name: I32 val
  • option_max_size: USize val = 4

Returns


getsockopt_u32

[Source]

Wrapper for getsockopt(2) where the kernel returns a C uint32_t.

Returns a 2-tuple: on success, (0, value). On failure, (errno, undefined) — the second element must be ignored. Only meaningful on a connected socket — returns (1, 0) if the connection is not open.

For commonly-tuned options, prefer the dedicated convenience methods (get_so_rcvbuf, get_so_sndbuf, etc.). Do not change the socket's non-blocking mode — lori's event-driven I/O requires non-blocking sockets.

fun box getsockopt_u32(
  level: I32 val,
  option_name: I32 val)
: (U32 val , U32 val)

Parameters

  • level: I32 val
  • option_name: I32 val

Returns


setsockopt

[Source]

General interface to setsockopt(2) for setting any socket option.

The caller is responsible for the correct size, byte contents, and byte order of the option array for the requested level and option_name.

Returns 0 on success, or the value of errno on failure. Only meaningful on a connected socket — returns non-zero if the connection is not open.

For commonly-tuned options, prefer the dedicated convenience methods (set_nodelay, set_so_rcvbuf, etc.). Do not change the socket's non-blocking mode — lori's event-driven I/O requires non-blocking sockets.

fun box setsockopt(
  level: I32 val,
  option_name: I32 val,
  option: Array[U8 val] ref)
: U32 val

Parameters

Returns


setsockopt_u32

[Source]

Wrapper for setsockopt(2) where the kernel expects a C uint32_t.

Returns 0 on success, or the value of errno on failure. Only meaningful on a connected socket — returns non-zero if the connection is not open.

For commonly-tuned options, prefer the dedicated convenience methods (set_nodelay, set_so_rcvbuf, etc.). Do not change the socket's non-blocking mode — lori's event-driven I/O requires non-blocking sockets.

fun box setsockopt_u32(
  level: I32 val,
  option_name: I32 val,
  option: U32 val)
: U32 val

Parameters

  • level: I32 val
  • option_name: I32 val
  • option: U32 val

Returns


idle_timeout

[Source]

Set or disable the idle timeout. Idle timeout is disabled by default.

When duration is an IdleTimeout, the timer fires when no successful send or receive occurs for that duration, delivering _on_idle_timeout() to the lifecycle event receiver. When duration is None, the idle timeout is disabled.

The timer re-arms after each firing while the connection is open. Both hard_close() and close() cancel it.

Can be called before the connection is established — the value is stored and the timer starts when the connection is ready.

This is independent of TCP keepalive (keepalive()). TCP keepalive is a transport-level probe that detects dead peers. Idle timeout is application-level inactivity detection — it fires whether or not the peer is alive.

If the idle timer's ASIO event subscription fails asynchronously (e.g. ENOMEM from kevent/epoll_ctl), the timer is cancelled and _on_idle_timer_failure() is dispatched to the lifecycle event receiver.

fun ref idle_timeout(
  duration: (IdleTimeout | None val))
: None val

Parameters

Returns


set_timer

[Source]

Create a one-shot timer that fires _on_timer() after the configured duration. Returns a TimerToken on success, or a SetTimerError on failure.

Unlike idle_timeout(), this timer has no I/O-reset behavior — it fires unconditionally after the duration elapses, regardless of send/receive activity. There is no automatic re-arming; call set_timer() again from _on_timer() for repetition.

Only one user timer can be active at a time. Setting a timer while one is already active returns SetTimerAlreadyActive — call cancel_timer() first. This prevents silent token invalidation.

Requires the connection to be application-level connected: the connection must be open and the initial SSL handshake (if any) must have completed. TLS upgrades via start_tls() do not block timer creation.

The timer survives close() (graceful shutdown) but is cancelled by hard_close().

User timers have two error paths. This method returns a SetTimerError synchronously when preconditions prevent the timer from being created (see the return type). When creation succeeds but the ASIO event subscription later fails (e.g. ENOMEM from kevent/epoll_ctl), _on_timer_failure() is dispatched to the lifecycle event receiver.

fun ref set_timer(
  duration: TimerDuration)
: (TimerToken val | SetTimerError)

Parameters

Returns


cancel_timer

[Source]

Cancel an active timer. No-op if the token doesn't match the active timer (already fired, already cancelled, wrong token). Safe to call with stale tokens.

No connection state check — timers can be cancelled during graceful shutdown (_Closing) since they remain active until hard_close().

fun ref cancel_timer(
  token: TimerToken val)
: None val

Parameters

Returns


set_read_buffer_minimum

[Source]

Set the shrink-back floor for the read buffer to exactly new_min bytes. When the read buffer is empty and larger than the minimum, it shrinks back to this size automatically. If the current buffer allocation is smaller than new_min, the buffer is grown to match.

Returns ReadBufferResizeBelowBufferSize if new_min is less than the current buffer-until value.

fun ref set_read_buffer_minimum(
  new_min: ReadBufferSize)
: (ReadBufferResized val | ReadBufferResizeBelowBufferSize val)

Parameters

Returns


resize_read_buffer

[Source]

Force the read buffer to exactly size' bytes, reallocating if different. If size' is below the current minimum, the minimum is lowered to match.

Returns ReadBufferResizeBelowBufferSize if size' is less than the current buffer-until value, or ReadBufferResizeBelowUsed if size' is less than the amount of unprocessed data currently in the buffer.

fun ref resize_read_buffer(
  size': ReadBufferSize)
: ReadBufferResizeResult

Parameters

Returns


local_address

[Source]

Return the local IP address. If this TCPConnection is closed then the address returned is invalid.

fun ref local_address()
: NetAddress val

Returns


remote_address

[Source]

Return the remote IP address. If this TCPConnection is closed then the address returned is invalid.

fun ref remote_address()
: NetAddress val

Returns


mute

[Source]

Temporarily suspend reading off this TCPConnection until such time as unmute is called.

When called from _on_received, no further data is delivered. Whatever the connection has read but not yet delivered is held, and unmute delivers it before anything read off the socket afterward. This holds for plaintext and SSL connections alike.

Held data only survives to an unmute. Closing a muted connection drops it, because close on a muted connection hard closes and dispose always does.

fun ref mute()
: None val

Returns


unmute

[Source]

Start reading off this TCPConnection again after having been muted.

Reading resumes on a later turn, not during this call. Data held since the mute is delivered before anything read off the socket afterward.

fun ref unmute()
: None val

Returns


buffer_until

[Source]

Set the number of bytes to buffer before delivering data via _on_received. When qty is Streaming, all available data is delivered as it arrives.

Returns BufferSizeAboveMinimum if qty exceeds the current read buffer minimum. Raise the buffer minimum first, then set buffer_until.

fun ref buffer_until(
  qty: (BufferSize | Streaming val))
: BufferUntilResult

Parameters

Returns


close

[Source]

Gracefully close the connection. Data already handed to an accepted send() is delivered before the connection closes.

On a muted connection this is a hard close instead: it shuts down at once and drops undelivered data — both held reads and queued writes (the writes fail with _on_send_failed).

Closing before the connection is established abandons the attempt and delivers _on_connection_failure.

fun ref close()
: None val

Returns


hard_close

[Source]

When an error happens, do a non-graceful close.

fun ref hard_close()
: None val

Returns


is_closed

[Source]

Returns whether the connection is closed or closing.

fun box is_closed()
: Bool val

Returns


is_writeable

[Source]

Returns whether the socket can currently send.

fun box is_writeable()
: Bool val

Returns


start_tls

[Source]

Initiate a TLS handshake on an established plaintext connection. Returns None when the handshake has been started, or a StartTLSError if the upgrade cannot proceed (the connection is unchanged in that case).

Preconditions: the connection must be open, not already TLS, not muted, have no unprocessed data in the read buffer, and have no pending writes. The read buffer check prevents a man-in-the-middle from injecting pre-TLS data that the application would process as post-TLS (CVE-2021-23222).

On success, _on_tls_ready() fires when the handshake completes. During the handshake, send() returns SendErrorNotConnected. If the handshake fails, _on_tls_failure fires followed by _on_closed().

The host parameter is used for SNI (Server Name Indication) on client connections. Pass an empty string for server connections or when SNI is not needed.

fun ref start_tls(
  ssl_ctx: SSLContext val,
  host: String val = "")
: (None val | StartTLSError)

Parameters

Returns


send

[Source]

Send data on this connection. Accepts a single buffer (ByteSeq) or multiple buffers (ByteSeqIter). When multiple buffers are provided, they are sent in a single syscall — avoiding both per-buffer syscall overhead and the cost of copying into a contiguous buffer.

Returns SendAccepted on success, or a SendError explaining the failure. On success _on_send_accepted(token, data) has already fired, from inside this call and before the bytes were written. That token gets exactly one further callback: _on_sent(token) once the data has been handed to the OS (written to the kernel send buffer, not received by the peer), or _on_send_failed(token) if the connection is lost or hard-closed before the bytes are written. A graceful close() sends what's still queued, so those sends fire _on_sent, not _on_send_failed. Closing the connection from any callback that runs inside this call does not change the return: the send stays accepted.

Both callbacks can run before this returns, so anything the calling code updates after the call -- a counter, a map, a flag -- is not updated yet when they fire.

fun ref send(
  data: (ByteSeq | ByteSeqIter val))
: SendResult

Parameters

Returns


read_again

[Source]

fun ref read_again()
: None val

Returns