OTP :ssl-compatible client facade for the implemented ex_ssl feature subset.
This experimental client supports TLS 1.3 and explicit bounded TLS 1.2, binary raw sockets, passive and
active-once delivery, application ownership transfer, authenticated ALPN,
bounded streaming writes, and peer verification by default. These restricted
defaults differ from OTP. Unsupported options return explicit
{:error, {:options, reason}} errors.
STARTTLS callers must own a passive binary/raw TCP socket, fully consume and
validate the application's upgrade response, and reject any buffered plaintext.
Supply server_name_indication as the certificate reference DNS name, or use
ex_ssl: [reference_identity: {:ip, address} | {:dns_id, name}] to verify a
separate IP/DNS identity independently of SNI and the TCP destination. Once
upgrade is attempted, an owned socket is closed on failure; plaintext must
never resume. A socket belonging to another process is left untouched.
Summary
Functions
Permanently abandons application writes while retaining response reads.
Closes the connection. Closing an already closed handle succeeds.
Upgrades an owned passive binary/raw TCP socket with a prepared snapshot.
Attaches lifecycle authority to one prepared upgrade, without overriding policy.
Returns the supported non-secret connection metadata.
Transfers application ownership while the TLS process retains the TCP socket.
Enables bounded response reads during an application send.
Returns the authenticated ALPN selection, if the server negotiated one.
Returns the authenticated server leaf certificate as DER.
Returns the live TCP peer address and port.
Resolves and validates TLS configuration for a later TCP upgrade.
Receives available bytes for length 0, or exactly length bytes. Timeout retains buffered data.
Writes iodata as one ordered logical write. Concurrent writes return :busy.
Writes iodata under an absolute monotonic millisecond deadline.
Changes supported delivery, send, and mutable TCP options after validation.
Returns the live local TCP address and port.
Functions
@spec abandon_send(SSL.Socket.t()) :: :ok | {:error, term()}
Permanently abandons application writes while retaining response reads.
Only the controlling owner may call this on an established connection. An
admitted send settles as {:error, :write_abandoned}; unsent plaintext is discarded and
future sends are rejected. A bounded already-protected application output job may
still finish its original transport write under its original finite deadline.
The job may include an automatic KeyUpdate followed by one application record. It is
never re-encrypted or replayed. At most one already-protected mandatory control
response may wait behind it, retaining committed traffic-key epochs and the
original finite deadline. Reads keep their existing byte bounds. Explicit close,
cancellation and owner loss abort both outputs.
Call close/1 after consuming the response, or to abort the pending record.
Ordinary sender death continues to fail the connection closed unless the owner
explicitly abandons writes before the sender dies.
@spec close(SSL.Socket.t()) :: :ok | {:error, term()}
Closes the connection. Closing an already closed handle succeeds.
@spec connect(:gen_tcp.socket(), list()) :: {:ok, SSL.Socket.t()} | {:error, term()}
@spec connect(term(), term(), term()) :: {:ok, SSL.Socket.t()} | {:error, term()}
@spec connect(term(), :inet.port_number(), list(), timeout()) :: {:ok, SSL.Socket.t()} | {:error, term()}
@spec connect_prepared(:gen_tcp.socket(), SSL.PreparedUpgrade.t(), timeout()) :: {:ok, SSL.Socket.t()} | {:error, term()}
Upgrades an owned passive binary/raw TCP socket with a prepared snapshot.
Uses the resolved policy without rereading files or resolving options/profiles.
Ownership, pending-plaintext rejection, timeout and close-on-failure semantics
are the same as connect/3. Future runtime or handshake failures remain possible.
@spec connect_prepared( :gen_tcp.socket(), SSL.PreparedUpgrade.t(), keyword(), timeout() ) :: {:ok, SSL.Socket.t()} | {:error, term()}
Attaches lifecycle authority to one prepared upgrade, without overriding policy.
@spec connection_information(SSL.Socket.t()) :: {:ok, keyword()} | {:error, term()}
Returns the supported non-secret connection metadata.
@spec connection_information(SSL.Socket.t(), term()) :: {:ok, keyword()} | {:error, term()}
@spec controlling_process(SSL.Socket.t(), pid()) :: :ok | {:error, term()}
Transfers application ownership while the TLS process retains the TCP socket.
@spec enable_duplex_reads(SSL.Socket.t()) :: :ok | {:error, term()}
Enables bounded response reads during an application send.
This owner-only, idempotent operation applies to an established open socket. It requires a finite send timeout and rejects later infinite-timeout sends. Reads may progress while one already-protected application output job is pending. At most one already-protected mandatory control response may wait behind that job under the original absolute write deadline. Handshake, control and shutdown output barriers remain in place; waiting grants no new budget. Normal sender death still fails the connection closed.
@spec negotiated_protocol(SSL.Socket.t()) :: {:ok, binary()} | {:error, term()}
Returns the authenticated ALPN selection, if the server negotiated one.
@spec peercert(SSL.Socket.t()) :: {:ok, binary()} | {:error, term()}
Returns the authenticated server leaf certificate as DER.
@spec peername(SSL.Socket.t()) :: {:ok, {:inet.ip_address(), :inet.port_number()}} | {:error, term()}
Returns the live TCP peer address and port.
@spec prepare_upgrade(term()) :: {:ok, SSL.PreparedUpgrade.t()} | {:error, term()}
Resolves and validates TLS configuration for a later TCP upgrade.
Loads trust and client credentials and freezes the upgrade reference, SNI and concrete wire profile. No socket, connection process or ephemeral keys are allocated. The returned opaque snapshot can be reused deliberately; connection randomness, ephemeral keys and session-ticket binders are generated at attach. This configuration snapshot is not an attempt/adoption or cleanup receipt.
@spec recv(SSL.Socket.t(), non_neg_integer(), timeout()) :: {:ok, binary()} | {:error, term()}
Receives available bytes for length 0, or exactly length bytes. Timeout retains buffered data.
@spec send(SSL.Socket.t(), iodata()) :: :ok | {:error, term()}
Writes iodata as one ordered logical write. Concurrent writes return :busy.
@spec send(SSL.Socket.t(), iodata(), {:abs_ms, integer()}) :: :ok | {:error, term()}
Writes iodata under an absolute monotonic millisecond deadline.
The deadline includes reservation and every protected record of this logical write. The controlling owner's configured send timeout may shorten it. This operation does not change the socket's owner or configured timeout.
@spec setopts(SSL.Socket.t(), list()) :: :ok | {:error, term()}
Changes supported delivery, send, and mutable TCP options after validation.
@spec sockname(SSL.Socket.t()) :: {:ok, {:inet.ip_address(), :inet.port_number()}} | {:error, term()}
Returns the live local TCP address and port.